swdmover.c revision 1.14 1 1.14 christos /* $NetBSD: swdmover.c,v 1.14 2017/01/07 21:11:14 christos Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*
4 1.5 thorpej * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
5 1.1 thorpej * All rights reserved.
6 1.1 thorpej *
7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 1.1 thorpej *
9 1.1 thorpej * Redistribution and use in source and binary forms, with or without
10 1.1 thorpej * modification, are permitted provided that the following conditions
11 1.1 thorpej * are met:
12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
13 1.1 thorpej * notice, this list of conditions and the following disclaimer.
14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
16 1.1 thorpej * documentation and/or other materials provided with the distribution.
17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software
18 1.1 thorpej * must display the following acknowledgement:
19 1.1 thorpej * This product includes software developed for the NetBSD Project by
20 1.1 thorpej * Wasabi Systems, Inc.
21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.1 thorpej * or promote products derived from this software without specific prior
23 1.1 thorpej * written permission.
24 1.1 thorpej *
25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE.
36 1.1 thorpej */
37 1.1 thorpej
38 1.1 thorpej /*
39 1.1 thorpej * swdmover.c: Software back-end providing the dmover functions
40 1.1 thorpej * mentioned in dmover(9).
41 1.1 thorpej *
42 1.1 thorpej * This module provides a fallback for cases where no hardware
43 1.1 thorpej * data movers are present in a system, and also serves an an
44 1.1 thorpej * example of how to write a dmover back-end.
45 1.1 thorpej *
46 1.1 thorpej * Note that even through the software dmover doesn't require
47 1.1 thorpej * interrupts to be blocked, we block them anyway to demonstrate
48 1.1 thorpej * the locking protocol.
49 1.1 thorpej */
50 1.1 thorpej
51 1.1 thorpej #include <sys/cdefs.h>
52 1.14 christos __KERNEL_RCSID(0, "$NetBSD: swdmover.c,v 1.14 2017/01/07 21:11:14 christos Exp $");
53 1.1 thorpej
54 1.1 thorpej #include <sys/param.h>
55 1.1 thorpej #include <sys/kthread.h>
56 1.1 thorpej #include <sys/systm.h>
57 1.1 thorpej #include <sys/uio.h>
58 1.1 thorpej
59 1.1 thorpej #include <dev/dmover/dmovervar.h>
60 1.1 thorpej
61 1.13 christos #include "ioconf.h"
62 1.13 christos
63 1.1 thorpej struct swdmover_function {
64 1.1 thorpej void (*sdf_process)(struct dmover_request *);
65 1.1 thorpej };
66 1.1 thorpej
67 1.1 thorpej static struct dmover_backend swdmover_backend;
68 1.11 he static struct lwp *swdmover_lwp;
69 1.1 thorpej static int swdmover_cv;
70 1.1 thorpej
71 1.1 thorpej /*
72 1.1 thorpej * swdmover_process:
73 1.1 thorpej *
74 1.1 thorpej * Dmover back-end entry point.
75 1.1 thorpej */
76 1.1 thorpej static void
77 1.1 thorpej swdmover_process(struct dmover_backend *dmb)
78 1.1 thorpej {
79 1.1 thorpej int s;
80 1.1 thorpej
81 1.1 thorpej /*
82 1.1 thorpej * Just wake up the processing thread. This will allow
83 1.1 thorpej * requests to linger on the middle-end's queue so that
84 1.1 thorpej * they can be cancelled, if need-be.
85 1.1 thorpej */
86 1.1 thorpej s = splbio();
87 1.1 thorpej /* XXXLOCK */
88 1.1 thorpej if (TAILQ_EMPTY(&dmb->dmb_pendreqs) == 0)
89 1.1 thorpej wakeup(&swdmover_cv);
90 1.1 thorpej /* XXXUNLOCK */
91 1.1 thorpej splx(s);
92 1.1 thorpej }
93 1.1 thorpej
94 1.1 thorpej /*
95 1.1 thorpej * swdmover_thread:
96 1.1 thorpej *
97 1.1 thorpej * Request processing thread.
98 1.1 thorpej */
99 1.1 thorpej static void
100 1.1 thorpej swdmover_thread(void *arg)
101 1.1 thorpej {
102 1.1 thorpej struct dmover_backend *dmb = arg;
103 1.1 thorpej struct dmover_request *dreq;
104 1.1 thorpej struct swdmover_function *sdf;
105 1.1 thorpej int s;
106 1.1 thorpej
107 1.1 thorpej s = splbio();
108 1.1 thorpej /* XXXLOCK */
109 1.1 thorpej
110 1.1 thorpej for (;;) {
111 1.1 thorpej dreq = TAILQ_FIRST(&dmb->dmb_pendreqs);
112 1.1 thorpej if (dreq == NULL) {
113 1.1 thorpej /* XXXUNLOCK */
114 1.1 thorpej (void) tsleep(&swdmover_cv, PRIBIO, "swdmvr", 0);
115 1.1 thorpej continue;
116 1.1 thorpej }
117 1.1 thorpej
118 1.1 thorpej dmover_backend_remque(dmb, dreq);
119 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_RUNNING;
120 1.1 thorpej
121 1.1 thorpej /* XXXUNLOCK */
122 1.1 thorpej splx(s);
123 1.1 thorpej
124 1.1 thorpej sdf = dreq->dreq_assignment->das_algdesc->dad_data;
125 1.1 thorpej (*sdf->sdf_process)(dreq);
126 1.1 thorpej
127 1.1 thorpej s = splbio();
128 1.1 thorpej /* XXXLOCK */
129 1.1 thorpej }
130 1.1 thorpej }
131 1.1 thorpej
132 1.1 thorpej /*
133 1.1 thorpej * swdmover_func_zero_process:
134 1.1 thorpej *
135 1.1 thorpej * Processing routine for the "zero" function.
136 1.1 thorpej */
137 1.1 thorpej static void
138 1.1 thorpej swdmover_func_zero_process(struct dmover_request *dreq)
139 1.1 thorpej {
140 1.1 thorpej
141 1.1 thorpej switch (dreq->dreq_outbuf_type) {
142 1.1 thorpej case DMOVER_BUF_LINEAR:
143 1.1 thorpej memset(dreq->dreq_outbuf.dmbuf_linear.l_addr, 0,
144 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len);
145 1.1 thorpej break;
146 1.1 thorpej
147 1.1 thorpej case DMOVER_BUF_UIO:
148 1.1 thorpej {
149 1.1 thorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio;
150 1.14 christos char cp[1024];
151 1.1 thorpej size_t count, buflen;
152 1.1 thorpej int error;
153 1.1 thorpej
154 1.1 thorpej if (uio->uio_rw != UIO_READ) {
155 1.1 thorpej /* XXXLOCK */
156 1.1 thorpej dreq->dreq_error = EINVAL;
157 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
158 1.1 thorpej /* XXXUNLOCK */
159 1.1 thorpej break;
160 1.1 thorpej }
161 1.1 thorpej
162 1.1 thorpej buflen = uio->uio_resid;
163 1.14 christos if (buflen > sizeof(cp))
164 1.14 christos buflen = sizeof(cp);
165 1.1 thorpej memset(cp, 0, buflen);
166 1.1 thorpej
167 1.1 thorpej while ((count = uio->uio_resid) != 0) {
168 1.1 thorpej if (count > buflen)
169 1.1 thorpej count = buflen;
170 1.1 thorpej error = uiomove(cp, count, uio);
171 1.1 thorpej if (error) {
172 1.1 thorpej /* XXXLOCK */
173 1.1 thorpej dreq->dreq_error = error;
174 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
175 1.1 thorpej /* XXXUNLOCK */
176 1.1 thorpej break;
177 1.1 thorpej }
178 1.1 thorpej }
179 1.1 thorpej break;
180 1.1 thorpej }
181 1.3 thorpej
182 1.3 thorpej default:
183 1.3 thorpej /* XXXLOCK */
184 1.3 thorpej dreq->dreq_error = EINVAL;
185 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
186 1.3 thorpej /* XXXUNLOCK */
187 1.1 thorpej }
188 1.1 thorpej
189 1.1 thorpej dmover_done(dreq);
190 1.1 thorpej }
191 1.1 thorpej
192 1.1 thorpej /*
193 1.1 thorpej * swdmover_func_fill8_process:
194 1.1 thorpej *
195 1.1 thorpej * Processing routine for the "fill8" function.
196 1.1 thorpej */
197 1.1 thorpej static void
198 1.1 thorpej swdmover_func_fill8_process(struct dmover_request *dreq)
199 1.1 thorpej {
200 1.1 thorpej
201 1.1 thorpej switch (dreq->dreq_outbuf_type) {
202 1.1 thorpej case DMOVER_BUF_LINEAR:
203 1.1 thorpej memset(dreq->dreq_outbuf.dmbuf_linear.l_addr,
204 1.1 thorpej dreq->dreq_immediate[0],
205 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len);
206 1.1 thorpej break;
207 1.1 thorpej
208 1.1 thorpej case DMOVER_BUF_UIO:
209 1.1 thorpej {
210 1.1 thorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio;
211 1.14 christos char cp[1024];
212 1.1 thorpej size_t count, buflen;
213 1.1 thorpej int error;
214 1.1 thorpej
215 1.1 thorpej if (uio->uio_rw != UIO_READ) {
216 1.1 thorpej /* XXXLOCK */
217 1.1 thorpej dreq->dreq_error = EINVAL;
218 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
219 1.1 thorpej /* XXXUNLOCK */
220 1.1 thorpej break;
221 1.1 thorpej }
222 1.1 thorpej
223 1.1 thorpej buflen = uio->uio_resid;
224 1.14 christos if (buflen > sizeof(cp))
225 1.14 christos buflen = sizeof(cp);
226 1.1 thorpej memset(cp, dreq->dreq_immediate[0], buflen);
227 1.1 thorpej
228 1.1 thorpej while ((count = uio->uio_resid) != 0) {
229 1.1 thorpej if (count > buflen)
230 1.1 thorpej count = buflen;
231 1.1 thorpej error = uiomove(cp, count, uio);
232 1.1 thorpej if (error) {
233 1.1 thorpej /* XXXLOCK */
234 1.1 thorpej dreq->dreq_error = error;
235 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
236 1.1 thorpej /* XXXUNLOCK */
237 1.1 thorpej break;
238 1.1 thorpej }
239 1.1 thorpej }
240 1.1 thorpej break;
241 1.1 thorpej }
242 1.3 thorpej
243 1.3 thorpej default:
244 1.3 thorpej /* XXXLOCK */
245 1.3 thorpej dreq->dreq_error = EINVAL;
246 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
247 1.3 thorpej /* XXXUNLOCK */
248 1.1 thorpej }
249 1.1 thorpej
250 1.1 thorpej dmover_done(dreq);
251 1.1 thorpej }
252 1.1 thorpej
253 1.6 briggs static void
254 1.6 briggs xor2(uint8_t *dst, uint8_t *src1, uint8_t *src2, int cnt)
255 1.6 briggs {
256 1.6 briggs
257 1.6 briggs while (cnt--)
258 1.6 briggs *dst++ = *src1++ ^ *src2++;
259 1.6 briggs }
260 1.6 briggs
261 1.6 briggs /*
262 1.6 briggs * swdmover_func_xor_process:
263 1.6 briggs *
264 1.6 briggs * Processing routine for the "xor" function.
265 1.6 briggs */
266 1.6 briggs static void
267 1.6 briggs swdmover_func_xor_process(struct dmover_request *dreq)
268 1.6 briggs {
269 1.6 briggs #define INBUF_L(x) dreq->dreq_inbuf[(x)].dmbuf_linear
270 1.6 briggs #define OUTBUF_L dreq->dreq_outbuf.dmbuf_linear
271 1.6 briggs
272 1.6 briggs uint32_t *dst32, *src32;
273 1.6 briggs uint8_t *dst8, *src8;
274 1.6 briggs int i, ninputs = dreq->dreq_assignment->das_algdesc->dad_ninputs;
275 1.6 briggs int aligned, len, nwords;
276 1.6 briggs
277 1.6 briggs /* XXX Currently, both buffers must be of same type. */
278 1.6 briggs if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) {
279 1.6 briggs /* XXXLOCK */
280 1.6 briggs dreq->dreq_error = EINVAL;
281 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
282 1.6 briggs /* XXXUNLOCK */
283 1.6 briggs goto done;
284 1.6 briggs }
285 1.6 briggs
286 1.6 briggs switch (dreq->dreq_outbuf_type) {
287 1.6 briggs case DMOVER_BUF_LINEAR:
288 1.6 briggs aligned = 1;
289 1.6 briggs if ((ulong) OUTBUF_L.l_addr & 0x3)
290 1.6 briggs aligned = 0;
291 1.7 briggs len = OUTBUF_L.l_len;
292 1.6 briggs for (i = 0 ; i < ninputs ; i++) {
293 1.6 briggs if (len != INBUF_L(i).l_len) {
294 1.6 briggs /* XXXLOCK */
295 1.6 briggs dreq->dreq_error = EINVAL;
296 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
297 1.6 briggs /* XXXUNLOCK */
298 1.6 briggs break;
299 1.6 briggs }
300 1.6 briggs if ((ulong) INBUF_L(i).l_addr & 0x3)
301 1.6 briggs aligned = 0;
302 1.6 briggs }
303 1.6 briggs if (aligned) {
304 1.6 briggs dst32 = (uint32_t *) OUTBUF_L.l_addr;
305 1.6 briggs nwords = len / 4;
306 1.6 briggs while (nwords--) {
307 1.6 briggs *dst32 = 0;
308 1.6 briggs for (i = 0 ; i < ninputs ; i++) {
309 1.6 briggs src32 = (uint32_t *) INBUF_L(i).l_addr;
310 1.6 briggs *dst32 ^= *src32;
311 1.6 briggs }
312 1.6 briggs dst32++;
313 1.6 briggs len -= 4;
314 1.6 briggs }
315 1.6 briggs }
316 1.6 briggs if (len) {
317 1.6 briggs dst8 = (uint8_t *) OUTBUF_L.l_addr;
318 1.6 briggs while (len--) {
319 1.6 briggs *dst8 = 0;
320 1.6 briggs for (i = 0 ; i < ninputs ; i++) {
321 1.6 briggs src8 = (uint8_t *) INBUF_L(i).l_addr;
322 1.6 briggs *dst8 ^= *src8;
323 1.6 briggs }
324 1.6 briggs dst8++;
325 1.6 briggs }
326 1.6 briggs }
327 1.8 perry
328 1.6 briggs break;
329 1.6 briggs
330 1.6 briggs case DMOVER_BUF_UIO:
331 1.6 briggs {
332 1.6 briggs struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio;
333 1.6 briggs struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
334 1.6 briggs struct uio *uio;
335 1.14 christos char cp[1024], dst[1024];
336 1.6 briggs size_t count, buflen;
337 1.6 briggs int error;
338 1.6 briggs
339 1.6 briggs if (uio_in->uio_rw != UIO_WRITE ||
340 1.6 briggs uio_out->uio_rw != UIO_READ ||
341 1.6 briggs uio_in->uio_resid != uio_out->uio_resid) {
342 1.6 briggs /* XXXLOCK */
343 1.6 briggs dreq->dreq_error = EINVAL;
344 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
345 1.6 briggs /* XXXUNLOCK */
346 1.6 briggs break;
347 1.6 briggs }
348 1.6 briggs
349 1.6 briggs buflen = uio_in->uio_resid;
350 1.14 christos if (buflen > sizeof(cp))
351 1.14 christos buflen = sizeof(cp);
352 1.6 briggs
353 1.6 briggs /*
354 1.6 briggs * For each block, copy first input buffer into the destination
355 1.6 briggs * buffer and then read the rest, one by one, into a temporary
356 1.6 briggs * buffer and xor into the destination buffer. After all of
357 1.6 briggs * the inputs have been xor'd in, move the destination buffer
358 1.6 briggs * out and loop.
359 1.6 briggs */
360 1.6 briggs while ((count = uio_in->uio_resid) != 0) {
361 1.6 briggs if (count > buflen)
362 1.6 briggs count = buflen;
363 1.6 briggs error = uiomove(dst, count, uio_in);
364 1.6 briggs if (error) {
365 1.6 briggs /* XXXLOCK */
366 1.6 briggs dreq->dreq_error = error;
367 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
368 1.6 briggs /* XXXUNLOCK */
369 1.6 briggs break;
370 1.6 briggs }
371 1.6 briggs for (i=1 ; (i < ninputs) && (error == 0) ; i++) {
372 1.6 briggs uio = dreq->dreq_inbuf[i].dmbuf_uio;
373 1.6 briggs error = uiomove(cp, count, uio);
374 1.6 briggs if (error == 0) {
375 1.6 briggs xor2(dst, dst, cp, count);
376 1.6 briggs }
377 1.6 briggs }
378 1.6 briggs if (error == 0) {
379 1.6 briggs error = uiomove(dst, count, uio_out);
380 1.6 briggs } else {
381 1.6 briggs /* XXXLOCK */
382 1.6 briggs dreq->dreq_error = error;
383 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
384 1.6 briggs /* XXXUNLOCK */
385 1.6 briggs break;
386 1.6 briggs }
387 1.6 briggs }
388 1.6 briggs break;
389 1.6 briggs }
390 1.6 briggs
391 1.6 briggs default:
392 1.6 briggs /* XXXLOCK */
393 1.6 briggs dreq->dreq_error = EINVAL;
394 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
395 1.6 briggs /* XXXUNLOCK */
396 1.6 briggs }
397 1.6 briggs
398 1.6 briggs done:
399 1.6 briggs dmover_done(dreq);
400 1.6 briggs }
401 1.6 briggs
402 1.1 thorpej /*
403 1.1 thorpej * swdmover_func_copy_process:
404 1.1 thorpej *
405 1.1 thorpej * Processing routine for the "copy" function.
406 1.1 thorpej */
407 1.1 thorpej static void
408 1.1 thorpej swdmover_func_copy_process(struct dmover_request *dreq)
409 1.1 thorpej {
410 1.1 thorpej
411 1.4 thorpej /* XXX Currently, both buffers must be of same type. */
412 1.4 thorpej if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) {
413 1.4 thorpej /* XXXLOCK */
414 1.4 thorpej dreq->dreq_error = EINVAL;
415 1.4 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
416 1.4 thorpej /* XXXUNLOCK */
417 1.4 thorpej goto done;
418 1.4 thorpej }
419 1.4 thorpej
420 1.1 thorpej switch (dreq->dreq_outbuf_type) {
421 1.1 thorpej case DMOVER_BUF_LINEAR:
422 1.1 thorpej if (dreq->dreq_outbuf.dmbuf_linear.l_len !=
423 1.1 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_len) {
424 1.1 thorpej /* XXXLOCK */
425 1.1 thorpej dreq->dreq_error = EINVAL;
426 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
427 1.1 thorpej /* XXXUNLOCK */
428 1.1 thorpej break;
429 1.1 thorpej }
430 1.1 thorpej memcpy(dreq->dreq_outbuf.dmbuf_linear.l_addr,
431 1.1 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
432 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len);
433 1.1 thorpej break;
434 1.1 thorpej
435 1.1 thorpej case DMOVER_BUF_UIO:
436 1.1 thorpej {
437 1.1 thorpej struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio;
438 1.1 thorpej struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
439 1.14 christos char cp[1024];
440 1.1 thorpej size_t count, buflen;
441 1.1 thorpej int error;
442 1.1 thorpej
443 1.1 thorpej if (uio_in->uio_rw != UIO_WRITE ||
444 1.1 thorpej uio_out->uio_rw != UIO_READ ||
445 1.1 thorpej uio_in->uio_resid != uio_out->uio_resid) {
446 1.1 thorpej /* XXXLOCK */
447 1.1 thorpej dreq->dreq_error = EINVAL;
448 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
449 1.1 thorpej /* XXXUNLOCK */
450 1.1 thorpej break;
451 1.1 thorpej }
452 1.1 thorpej
453 1.1 thorpej buflen = uio_in->uio_resid;
454 1.14 christos if (buflen > sizeof(cp))
455 1.14 christos buflen = sizeof(cp);
456 1.1 thorpej
457 1.1 thorpej while ((count = uio_in->uio_resid) != 0) {
458 1.1 thorpej if (count > buflen)
459 1.1 thorpej count = buflen;
460 1.1 thorpej error = uiomove(cp, count, uio_in);
461 1.1 thorpej if (error == 0)
462 1.1 thorpej error = uiomove(cp, count, uio_out);
463 1.1 thorpej if (error) {
464 1.1 thorpej /* XXXLOCK */
465 1.1 thorpej dreq->dreq_error = error;
466 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
467 1.1 thorpej /* XXXUNLOCK */
468 1.1 thorpej break;
469 1.1 thorpej }
470 1.1 thorpej }
471 1.1 thorpej break;
472 1.1 thorpej }
473 1.3 thorpej
474 1.3 thorpej default:
475 1.3 thorpej /* XXXLOCK */
476 1.3 thorpej dreq->dreq_error = EINVAL;
477 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
478 1.3 thorpej /* XXXUNLOCK */
479 1.1 thorpej }
480 1.1 thorpej
481 1.4 thorpej done:
482 1.1 thorpej dmover_done(dreq);
483 1.1 thorpej }
484 1.1 thorpej
485 1.5 thorpej static const uint32_t iscsi_crc32c_table[256] = {
486 1.5 thorpej 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
487 1.5 thorpej 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
488 1.5 thorpej 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
489 1.5 thorpej 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
490 1.5 thorpej 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
491 1.5 thorpej 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
492 1.5 thorpej 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
493 1.5 thorpej 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
494 1.5 thorpej 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
495 1.5 thorpej 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
496 1.5 thorpej 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
497 1.5 thorpej 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
498 1.5 thorpej 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
499 1.5 thorpej 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
500 1.5 thorpej 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
501 1.5 thorpej 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
502 1.5 thorpej 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
503 1.5 thorpej 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
504 1.5 thorpej 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
505 1.5 thorpej 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
506 1.5 thorpej 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
507 1.5 thorpej 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
508 1.5 thorpej 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
509 1.5 thorpej 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
510 1.5 thorpej 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
511 1.5 thorpej 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
512 1.5 thorpej 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
513 1.5 thorpej 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
514 1.5 thorpej 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
515 1.5 thorpej 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
516 1.5 thorpej 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
517 1.5 thorpej 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
518 1.5 thorpej 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
519 1.5 thorpej 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
520 1.5 thorpej 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
521 1.5 thorpej 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
522 1.5 thorpej 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
523 1.5 thorpej 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
524 1.5 thorpej 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
525 1.5 thorpej 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
526 1.5 thorpej 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
527 1.5 thorpej 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
528 1.5 thorpej 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
529 1.5 thorpej 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
530 1.5 thorpej 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
531 1.5 thorpej 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
532 1.5 thorpej 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
533 1.5 thorpej 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
534 1.5 thorpej 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
535 1.5 thorpej 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
536 1.5 thorpej 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
537 1.5 thorpej 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
538 1.5 thorpej 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
539 1.5 thorpej 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
540 1.5 thorpej 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
541 1.5 thorpej 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
542 1.5 thorpej 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
543 1.5 thorpej 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
544 1.5 thorpej 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
545 1.5 thorpej 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
546 1.5 thorpej 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
547 1.5 thorpej 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
548 1.5 thorpej 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
549 1.5 thorpej 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
550 1.5 thorpej };
551 1.5 thorpej
552 1.5 thorpej static uint32_t
553 1.5 thorpej iscsi_crc32c(const uint8_t *buf, size_t len, uint32_t last)
554 1.5 thorpej {
555 1.5 thorpej uint32_t crc = 0xffffffffU ^ last;
556 1.5 thorpej
557 1.5 thorpej while (len--)
558 1.5 thorpej crc = iscsi_crc32c_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8);
559 1.5 thorpej
560 1.5 thorpej return (crc ^ 0xffffffffU);
561 1.5 thorpej }
562 1.5 thorpej
563 1.5 thorpej /*
564 1.5 thorpej * swdmover_func_iscsi_crc32c_process:
565 1.5 thorpej *
566 1.5 thorpej * Processing routine for the "iscsi-crc32c" function.
567 1.5 thorpej */
568 1.5 thorpej static void
569 1.5 thorpej swdmover_func_iscsi_crc32c_process(struct dmover_request *dreq)
570 1.5 thorpej {
571 1.5 thorpej uint32_t result;
572 1.5 thorpej
573 1.5 thorpej /* No output buffer; we use the immediate only. */
574 1.5 thorpej if (dreq->dreq_outbuf_type != DMOVER_BUF_NONE) {
575 1.5 thorpej /* XXXLOCK */
576 1.5 thorpej dreq->dreq_error = EINVAL;
577 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
578 1.5 thorpej /* XXXUNLOCK */
579 1.5 thorpej goto done;
580 1.5 thorpej }
581 1.5 thorpej
582 1.5 thorpej memcpy(&result, dreq->dreq_immediate, sizeof(result));
583 1.5 thorpej
584 1.5 thorpej switch (dreq->dreq_inbuf_type) {
585 1.5 thorpej case DMOVER_BUF_LINEAR:
586 1.5 thorpej result = iscsi_crc32c(dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
587 1.5 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_len, result);
588 1.5 thorpej break;
589 1.5 thorpej
590 1.5 thorpej case DMOVER_BUF_UIO:
591 1.5 thorpej {
592 1.5 thorpej struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
593 1.14 christos uint8_t cp[1024];
594 1.5 thorpej size_t count, buflen;
595 1.5 thorpej int error;
596 1.5 thorpej
597 1.5 thorpej if (uio_in->uio_rw != UIO_WRITE) {
598 1.5 thorpej /* XXXLOCK */
599 1.5 thorpej dreq->dreq_error = EINVAL;
600 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
601 1.5 thorpej /* XXXUNLOCK */
602 1.5 thorpej goto done;
603 1.5 thorpej }
604 1.5 thorpej
605 1.5 thorpej buflen = uio_in->uio_resid;
606 1.14 christos if (buflen > sizeof(cp))
607 1.14 christos buflen = sizeof(cp);
608 1.5 thorpej
609 1.5 thorpej while ((count = uio_in->uio_resid) != 0) {
610 1.5 thorpej if (count > buflen)
611 1.5 thorpej count = buflen;
612 1.5 thorpej error = uiomove(cp, count, uio_in);
613 1.5 thorpej if (error) {
614 1.5 thorpej /* XXXLOCK */
615 1.5 thorpej dreq->dreq_error = error;
616 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
617 1.5 thorpej /* XXXUNLOCK */
618 1.5 thorpej goto done;
619 1.5 thorpej } else
620 1.5 thorpej result = iscsi_crc32c(cp, count, result);
621 1.5 thorpej }
622 1.5 thorpej break;
623 1.5 thorpej }
624 1.5 thorpej
625 1.5 thorpej default:
626 1.5 thorpej /* XXXLOCK */
627 1.5 thorpej dreq->dreq_error = EINVAL;
628 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
629 1.5 thorpej /* XXXUNLOCK */
630 1.5 thorpej goto done;
631 1.5 thorpej }
632 1.5 thorpej
633 1.5 thorpej memcpy(dreq->dreq_immediate, &result, sizeof(result));
634 1.5 thorpej done:
635 1.5 thorpej dmover_done(dreq);
636 1.5 thorpej }
637 1.5 thorpej
638 1.1 thorpej static struct swdmover_function swdmover_func_zero = {
639 1.1 thorpej swdmover_func_zero_process
640 1.1 thorpej };
641 1.1 thorpej
642 1.1 thorpej static struct swdmover_function swdmover_func_fill8 = {
643 1.1 thorpej swdmover_func_fill8_process
644 1.1 thorpej };
645 1.1 thorpej
646 1.5 thorpej static struct swdmover_function swdmover_func_copy = {
647 1.1 thorpej swdmover_func_copy_process
648 1.1 thorpej };
649 1.1 thorpej
650 1.6 briggs static struct swdmover_function swdmover_func_xor = {
651 1.6 briggs swdmover_func_xor_process
652 1.6 briggs };
653 1.6 briggs
654 1.5 thorpej static struct swdmover_function swdmover_func_iscsi_crc32c = {
655 1.5 thorpej swdmover_func_iscsi_crc32c_process
656 1.5 thorpej };
657 1.5 thorpej
658 1.1 thorpej const struct dmover_algdesc swdmover_algdescs[] = {
659 1.6 briggs {
660 1.6 briggs DMOVER_FUNC_XOR2,
661 1.6 briggs &swdmover_func_xor,
662 1.6 briggs 2
663 1.6 briggs },
664 1.6 briggs {
665 1.6 briggs DMOVER_FUNC_XOR3,
666 1.6 briggs &swdmover_func_xor,
667 1.6 briggs 3
668 1.6 briggs },
669 1.6 briggs {
670 1.6 briggs DMOVER_FUNC_XOR4,
671 1.6 briggs &swdmover_func_xor,
672 1.6 briggs 4
673 1.6 briggs },
674 1.6 briggs {
675 1.6 briggs DMOVER_FUNC_XOR5,
676 1.6 briggs &swdmover_func_xor,
677 1.6 briggs 5
678 1.6 briggs },
679 1.6 briggs {
680 1.6 briggs DMOVER_FUNC_XOR6,
681 1.6 briggs &swdmover_func_xor,
682 1.6 briggs 6
683 1.6 briggs },
684 1.6 briggs {
685 1.6 briggs DMOVER_FUNC_XOR7,
686 1.6 briggs &swdmover_func_xor,
687 1.6 briggs 7
688 1.6 briggs },
689 1.6 briggs {
690 1.6 briggs DMOVER_FUNC_XOR8,
691 1.6 briggs &swdmover_func_xor,
692 1.6 briggs 8
693 1.6 briggs },
694 1.1 thorpej {
695 1.1 thorpej DMOVER_FUNC_ZERO,
696 1.1 thorpej &swdmover_func_zero,
697 1.1 thorpej 0
698 1.1 thorpej },
699 1.1 thorpej {
700 1.1 thorpej DMOVER_FUNC_FILL8,
701 1.1 thorpej &swdmover_func_fill8,
702 1.1 thorpej 0
703 1.1 thorpej },
704 1.1 thorpej {
705 1.1 thorpej DMOVER_FUNC_COPY,
706 1.1 thorpej &swdmover_func_copy,
707 1.1 thorpej 1
708 1.5 thorpej },
709 1.5 thorpej {
710 1.5 thorpej DMOVER_FUNC_ISCSI_CRC32C,
711 1.5 thorpej &swdmover_func_iscsi_crc32c,
712 1.5 thorpej 1,
713 1.1 thorpej },
714 1.1 thorpej };
715 1.1 thorpej #define SWDMOVER_ALGDESC_COUNT \
716 1.1 thorpej (sizeof(swdmover_algdescs) / sizeof(swdmover_algdescs[0]))
717 1.1 thorpej
718 1.1 thorpej /*
719 1.1 thorpej * swdmoverattach:
720 1.1 thorpej *
721 1.1 thorpej * Pesudo-device attach routine.
722 1.1 thorpej */
723 1.1 thorpej void
724 1.1 thorpej swdmoverattach(int count)
725 1.1 thorpej {
726 1.10 ad int error;
727 1.1 thorpej
728 1.1 thorpej swdmover_backend.dmb_name = "swdmover";
729 1.1 thorpej swdmover_backend.dmb_speed = 1; /* XXX */
730 1.1 thorpej swdmover_backend.dmb_cookie = NULL;
731 1.1 thorpej swdmover_backend.dmb_algdescs = swdmover_algdescs;
732 1.1 thorpej swdmover_backend.dmb_nalgdescs = SWDMOVER_ALGDESC_COUNT;
733 1.1 thorpej swdmover_backend.dmb_process = swdmover_process;
734 1.1 thorpej
735 1.10 ad error = kthread_create(PRI_NONE, 0, NULL, swdmover_thread,
736 1.11 he &swdmover_backend, &swdmover_lwp, "swdmover");
737 1.10 ad if (error)
738 1.10 ad printf("WARNING: unable to create swdmover thread, "
739 1.10 ad "error = %d\n", error);
740 1.1 thorpej
741 1.1 thorpej /* XXX Should only register this when kthread creation succeeds. */
742 1.1 thorpej dmover_backend_register(&swdmover_backend);
743 1.1 thorpej }
744