1*2a58b312SMartin Matuska /*
2*2a58b312SMartin Matuska * CDDL HEADER START
3*2a58b312SMartin Matuska *
4*2a58b312SMartin Matuska * The contents of this file are subject to the terms of the
5*2a58b312SMartin Matuska * Common Development and Distribution License (the "License").
6*2a58b312SMartin Matuska * You may not use this file except in compliance with the License.
7*2a58b312SMartin Matuska *
8*2a58b312SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2a58b312SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
10*2a58b312SMartin Matuska * See the License for the specific language governing permissions
11*2a58b312SMartin Matuska * and limitations under the License.
12*2a58b312SMartin Matuska *
13*2a58b312SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each
14*2a58b312SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2a58b312SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the
16*2a58b312SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying
17*2a58b312SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner]
18*2a58b312SMartin Matuska *
19*2a58b312SMartin Matuska * CDDL HEADER END
20*2a58b312SMartin Matuska */
21*2a58b312SMartin Matuska
22*2a58b312SMartin Matuska /*
23*2a58b312SMartin Matuska * Copyright (c) 2003, 2010 Oracle and/or its affiliates.
24*2a58b312SMartin Matuska * Copyright (c) 2022 Tino Reichardt <milky-zfs@mcmilk.de>
25*2a58b312SMartin Matuska */
26*2a58b312SMartin Matuska
27*2a58b312SMartin Matuska /*
28*2a58b312SMartin Matuska * This file gets included by c files for implementing the full set
29*2a58b312SMartin Matuska * of zfs_impl.h defines.
30*2a58b312SMartin Matuska *
31*2a58b312SMartin Matuska * It's ment for easier maintaining multiple implementations of
32*2a58b312SMartin Matuska * algorithms. Look into blake3_impl.c, sha256_impl.c or sha512_impl.c
33*2a58b312SMartin Matuska * for reference.
34*2a58b312SMartin Matuska */
35*2a58b312SMartin Matuska
36*2a58b312SMartin Matuska #include <sys/zfs_context.h>
37*2a58b312SMartin Matuska #include <sys/zio_checksum.h>
38*2a58b312SMartin Matuska #include <sys/zfs_impl.h>
39*2a58b312SMartin Matuska
40*2a58b312SMartin Matuska /* Two default implementations */
41*2a58b312SMartin Matuska #define IMPL_FASTEST (UINT32_MAX)
42*2a58b312SMartin Matuska #define IMPL_CYCLE (UINT32_MAX - 1)
43*2a58b312SMartin Matuska
44*2a58b312SMartin Matuska #define IMPL_READ(i) (*(volatile uint32_t *) &(i))
45*2a58b312SMartin Matuska
46*2a58b312SMartin Matuska /* Implementation that contains the fastest method */
47*2a58b312SMartin Matuska static IMPL_OPS_T generic_fastest_impl = {
48*2a58b312SMartin Matuska .name = "fastest"
49*2a58b312SMartin Matuska };
50*2a58b312SMartin Matuska
51*2a58b312SMartin Matuska /* Hold all supported implementations */
52*2a58b312SMartin Matuska static const IMPL_OPS_T *generic_supp_impls[ARRAY_SIZE(IMPL_ARRAY)];
53*2a58b312SMartin Matuska static uint32_t generic_supp_impls_cnt = 0;
54*2a58b312SMartin Matuska
55*2a58b312SMartin Matuska /* Currently selected implementation */
56*2a58b312SMartin Matuska static uint32_t generic_impl_chosen = IMPL_FASTEST;
57*2a58b312SMartin Matuska
58*2a58b312SMartin Matuska static struct generic_impl_selector {
59*2a58b312SMartin Matuska const char *name;
60*2a58b312SMartin Matuska uint32_t sel;
61*2a58b312SMartin Matuska } generic_impl_selectors[] = {
62*2a58b312SMartin Matuska { "cycle", IMPL_CYCLE },
63*2a58b312SMartin Matuska { "fastest", IMPL_FASTEST }
64*2a58b312SMartin Matuska };
65*2a58b312SMartin Matuska
66*2a58b312SMartin Matuska /* check the supported implementations */
67*2a58b312SMartin Matuska static void
generic_impl_init(void)68*2a58b312SMartin Matuska generic_impl_init(void)
69*2a58b312SMartin Matuska {
70*2a58b312SMartin Matuska int i, c;
71*2a58b312SMartin Matuska
72*2a58b312SMartin Matuska /* init only once */
73*2a58b312SMartin Matuska if (likely(generic_supp_impls_cnt != 0))
74*2a58b312SMartin Matuska return;
75*2a58b312SMartin Matuska
76*2a58b312SMartin Matuska /* Move supported implementations into generic_supp_impls */
77*2a58b312SMartin Matuska for (i = 0, c = 0; i < ARRAY_SIZE(IMPL_ARRAY); i++) {
78*2a58b312SMartin Matuska const IMPL_OPS_T *impl = IMPL_ARRAY[i];
79*2a58b312SMartin Matuska
80*2a58b312SMartin Matuska if (impl->is_supported && impl->is_supported())
81*2a58b312SMartin Matuska generic_supp_impls[c++] = impl;
82*2a58b312SMartin Matuska }
83*2a58b312SMartin Matuska generic_supp_impls_cnt = c;
84*2a58b312SMartin Matuska
85*2a58b312SMartin Matuska /* first init generic impl, may be changed via set_fastest() */
86*2a58b312SMartin Matuska memcpy(&generic_fastest_impl, generic_supp_impls[0],
87*2a58b312SMartin Matuska sizeof (generic_fastest_impl));
88*2a58b312SMartin Matuska }
89*2a58b312SMartin Matuska
90*2a58b312SMartin Matuska /* get number of supported implementations */
91*2a58b312SMartin Matuska static uint32_t
generic_impl_getcnt(void)92*2a58b312SMartin Matuska generic_impl_getcnt(void)
93*2a58b312SMartin Matuska {
94*2a58b312SMartin Matuska generic_impl_init();
95*2a58b312SMartin Matuska return (generic_supp_impls_cnt);
96*2a58b312SMartin Matuska }
97*2a58b312SMartin Matuska
98*2a58b312SMartin Matuska /* get id of selected implementation */
99*2a58b312SMartin Matuska static uint32_t
generic_impl_getid(void)100*2a58b312SMartin Matuska generic_impl_getid(void)
101*2a58b312SMartin Matuska {
102*2a58b312SMartin Matuska generic_impl_init();
103*2a58b312SMartin Matuska return (IMPL_READ(generic_impl_chosen));
104*2a58b312SMartin Matuska }
105*2a58b312SMartin Matuska
106*2a58b312SMartin Matuska /* get name of selected implementation */
107*2a58b312SMartin Matuska static const char *
generic_impl_getname(void)108*2a58b312SMartin Matuska generic_impl_getname(void)
109*2a58b312SMartin Matuska {
110*2a58b312SMartin Matuska uint32_t impl = IMPL_READ(generic_impl_chosen);
111*2a58b312SMartin Matuska
112*2a58b312SMartin Matuska generic_impl_init();
113*2a58b312SMartin Matuska switch (impl) {
114*2a58b312SMartin Matuska case IMPL_FASTEST:
115*2a58b312SMartin Matuska return ("fastest");
116*2a58b312SMartin Matuska case IMPL_CYCLE:
117*2a58b312SMartin Matuska return ("cycle");
118*2a58b312SMartin Matuska default:
119*2a58b312SMartin Matuska return (generic_supp_impls[impl]->name);
120*2a58b312SMartin Matuska }
121*2a58b312SMartin Matuska }
122*2a58b312SMartin Matuska
123*2a58b312SMartin Matuska /* set implementation by id */
124*2a58b312SMartin Matuska static void
generic_impl_setid(uint32_t id)125*2a58b312SMartin Matuska generic_impl_setid(uint32_t id)
126*2a58b312SMartin Matuska {
127*2a58b312SMartin Matuska generic_impl_init();
128*2a58b312SMartin Matuska switch (id) {
129*2a58b312SMartin Matuska case IMPL_FASTEST:
130*2a58b312SMartin Matuska atomic_swap_32(&generic_impl_chosen, IMPL_FASTEST);
131*2a58b312SMartin Matuska break;
132*2a58b312SMartin Matuska case IMPL_CYCLE:
133*2a58b312SMartin Matuska atomic_swap_32(&generic_impl_chosen, IMPL_CYCLE);
134*2a58b312SMartin Matuska break;
135*2a58b312SMartin Matuska default:
136*2a58b312SMartin Matuska ASSERT3U(id, <, generic_supp_impls_cnt);
137*2a58b312SMartin Matuska atomic_swap_32(&generic_impl_chosen, id);
138*2a58b312SMartin Matuska break;
139*2a58b312SMartin Matuska }
140*2a58b312SMartin Matuska }
141*2a58b312SMartin Matuska
142*2a58b312SMartin Matuska /* set implementation by name */
143*2a58b312SMartin Matuska static int
generic_impl_setname(const char * val)144*2a58b312SMartin Matuska generic_impl_setname(const char *val)
145*2a58b312SMartin Matuska {
146*2a58b312SMartin Matuska uint32_t impl = IMPL_READ(generic_impl_chosen);
147*2a58b312SMartin Matuska size_t val_len;
148*2a58b312SMartin Matuska int i, err = -EINVAL;
149*2a58b312SMartin Matuska
150*2a58b312SMartin Matuska generic_impl_init();
151*2a58b312SMartin Matuska val_len = strlen(val);
152*2a58b312SMartin Matuska while ((val_len > 0) && !!isspace(val[val_len-1])) /* trim '\n' */
153*2a58b312SMartin Matuska val_len--;
154*2a58b312SMartin Matuska
155*2a58b312SMartin Matuska /* check mandatory implementations */
156*2a58b312SMartin Matuska for (i = 0; i < ARRAY_SIZE(generic_impl_selectors); i++) {
157*2a58b312SMartin Matuska const char *name = generic_impl_selectors[i].name;
158*2a58b312SMartin Matuska
159*2a58b312SMartin Matuska if (val_len == strlen(name) &&
160*2a58b312SMartin Matuska strncmp(val, name, val_len) == 0) {
161*2a58b312SMartin Matuska impl = generic_impl_selectors[i].sel;
162*2a58b312SMartin Matuska err = 0;
163*2a58b312SMartin Matuska break;
164*2a58b312SMartin Matuska }
165*2a58b312SMartin Matuska }
166*2a58b312SMartin Matuska
167*2a58b312SMartin Matuska /* check all supported implementations */
168*2a58b312SMartin Matuska if (err != 0) {
169*2a58b312SMartin Matuska for (i = 0; i < generic_supp_impls_cnt; i++) {
170*2a58b312SMartin Matuska const char *name = generic_supp_impls[i]->name;
171*2a58b312SMartin Matuska
172*2a58b312SMartin Matuska if (val_len == strlen(name) &&
173*2a58b312SMartin Matuska strncmp(val, name, val_len) == 0) {
174*2a58b312SMartin Matuska impl = i;
175*2a58b312SMartin Matuska err = 0;
176*2a58b312SMartin Matuska break;
177*2a58b312SMartin Matuska }
178*2a58b312SMartin Matuska }
179*2a58b312SMartin Matuska }
180*2a58b312SMartin Matuska
181*2a58b312SMartin Matuska if (err == 0) {
182*2a58b312SMartin Matuska atomic_swap_32(&generic_impl_chosen, impl);
183*2a58b312SMartin Matuska }
184*2a58b312SMartin Matuska
185*2a58b312SMartin Matuska return (err);
186*2a58b312SMartin Matuska }
187*2a58b312SMartin Matuska
188*2a58b312SMartin Matuska /* setup id as fastest implementation */
189*2a58b312SMartin Matuska static void
generic_impl_set_fastest(uint32_t id)190*2a58b312SMartin Matuska generic_impl_set_fastest(uint32_t id)
191*2a58b312SMartin Matuska {
192*2a58b312SMartin Matuska generic_impl_init();
193*2a58b312SMartin Matuska memcpy(&generic_fastest_impl, generic_supp_impls[id],
194*2a58b312SMartin Matuska sizeof (generic_fastest_impl));
195*2a58b312SMartin Matuska }
196*2a58b312SMartin Matuska
197*2a58b312SMartin Matuska /* return impl iterating functions */
198*2a58b312SMartin Matuska const zfs_impl_t ZFS_IMPL_OPS = {
199*2a58b312SMartin Matuska .name = IMPL_NAME,
200*2a58b312SMartin Matuska .getcnt = generic_impl_getcnt,
201*2a58b312SMartin Matuska .getid = generic_impl_getid,
202*2a58b312SMartin Matuska .getname = generic_impl_getname,
203*2a58b312SMartin Matuska .set_fastest = generic_impl_set_fastest,
204*2a58b312SMartin Matuska .setid = generic_impl_setid,
205*2a58b312SMartin Matuska .setname = generic_impl_setname
206*2a58b312SMartin Matuska };
207*2a58b312SMartin Matuska
208*2a58b312SMartin Matuska /* get impl ops_t of selected implementation */
209*2a58b312SMartin Matuska const IMPL_OPS_T *
IMPL_GET_OPS(void)210*2a58b312SMartin Matuska IMPL_GET_OPS(void)
211*2a58b312SMartin Matuska {
212*2a58b312SMartin Matuska const IMPL_OPS_T *ops = NULL;
213*2a58b312SMartin Matuska uint32_t idx, impl = IMPL_READ(generic_impl_chosen);
214*2a58b312SMartin Matuska static uint32_t cycle_count = 0;
215*2a58b312SMartin Matuska
216*2a58b312SMartin Matuska generic_impl_init();
217*2a58b312SMartin Matuska switch (impl) {
218*2a58b312SMartin Matuska case IMPL_FASTEST:
219*2a58b312SMartin Matuska ops = &generic_fastest_impl;
220*2a58b312SMartin Matuska break;
221*2a58b312SMartin Matuska case IMPL_CYCLE:
222*2a58b312SMartin Matuska idx = (++cycle_count) % generic_supp_impls_cnt;
223*2a58b312SMartin Matuska ops = generic_supp_impls[idx];
224*2a58b312SMartin Matuska break;
225*2a58b312SMartin Matuska default:
226*2a58b312SMartin Matuska ASSERT3U(impl, <, generic_supp_impls_cnt);
227*2a58b312SMartin Matuska ops = generic_supp_impls[impl];
228*2a58b312SMartin Matuska break;
229*2a58b312SMartin Matuska }
230*2a58b312SMartin Matuska
231*2a58b312SMartin Matuska ASSERT3P(ops, !=, NULL);
232*2a58b312SMartin Matuska return (ops);
233*2a58b312SMartin Matuska }
234