swdmover.c revision 1.13 1 1.13 christos /* $NetBSD: swdmover.c,v 1.13 2015/08/20 14:40:17 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.13 christos __KERNEL_RCSID(0, "$NetBSD: swdmover.c,v 1.13 2015/08/20 14:40:17 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.1 thorpej char *cp;
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.1 thorpej if (buflen > 1024)
164 1.1 thorpej buflen = 1024;
165 1.1 thorpej cp = alloca(buflen);
166 1.1 thorpej memset(cp, 0, buflen);
167 1.1 thorpej
168 1.1 thorpej while ((count = uio->uio_resid) != 0) {
169 1.1 thorpej if (count > buflen)
170 1.1 thorpej count = buflen;
171 1.1 thorpej error = uiomove(cp, count, uio);
172 1.1 thorpej if (error) {
173 1.1 thorpej /* XXXLOCK */
174 1.1 thorpej dreq->dreq_error = error;
175 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
176 1.1 thorpej /* XXXUNLOCK */
177 1.1 thorpej break;
178 1.1 thorpej }
179 1.1 thorpej }
180 1.1 thorpej break;
181 1.1 thorpej }
182 1.3 thorpej
183 1.3 thorpej default:
184 1.3 thorpej /* XXXLOCK */
185 1.3 thorpej dreq->dreq_error = EINVAL;
186 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
187 1.3 thorpej /* XXXUNLOCK */
188 1.1 thorpej }
189 1.1 thorpej
190 1.1 thorpej dmover_done(dreq);
191 1.1 thorpej }
192 1.1 thorpej
193 1.1 thorpej /*
194 1.1 thorpej * swdmover_func_fill8_process:
195 1.1 thorpej *
196 1.1 thorpej * Processing routine for the "fill8" function.
197 1.1 thorpej */
198 1.1 thorpej static void
199 1.1 thorpej swdmover_func_fill8_process(struct dmover_request *dreq)
200 1.1 thorpej {
201 1.1 thorpej
202 1.1 thorpej switch (dreq->dreq_outbuf_type) {
203 1.1 thorpej case DMOVER_BUF_LINEAR:
204 1.1 thorpej memset(dreq->dreq_outbuf.dmbuf_linear.l_addr,
205 1.1 thorpej dreq->dreq_immediate[0],
206 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len);
207 1.1 thorpej break;
208 1.1 thorpej
209 1.1 thorpej case DMOVER_BUF_UIO:
210 1.1 thorpej {
211 1.1 thorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio;
212 1.1 thorpej char *cp;
213 1.1 thorpej size_t count, buflen;
214 1.1 thorpej int error;
215 1.1 thorpej
216 1.1 thorpej if (uio->uio_rw != UIO_READ) {
217 1.1 thorpej /* XXXLOCK */
218 1.1 thorpej dreq->dreq_error = EINVAL;
219 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
220 1.1 thorpej /* XXXUNLOCK */
221 1.1 thorpej break;
222 1.1 thorpej }
223 1.1 thorpej
224 1.1 thorpej buflen = uio->uio_resid;
225 1.1 thorpej if (buflen > 1024)
226 1.1 thorpej buflen = 1024;
227 1.1 thorpej cp = alloca(buflen);
228 1.1 thorpej memset(cp, dreq->dreq_immediate[0], buflen);
229 1.1 thorpej
230 1.1 thorpej while ((count = uio->uio_resid) != 0) {
231 1.1 thorpej if (count > buflen)
232 1.1 thorpej count = buflen;
233 1.1 thorpej error = uiomove(cp, count, uio);
234 1.1 thorpej if (error) {
235 1.1 thorpej /* XXXLOCK */
236 1.1 thorpej dreq->dreq_error = error;
237 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
238 1.1 thorpej /* XXXUNLOCK */
239 1.1 thorpej break;
240 1.1 thorpej }
241 1.1 thorpej }
242 1.1 thorpej break;
243 1.1 thorpej }
244 1.3 thorpej
245 1.3 thorpej default:
246 1.3 thorpej /* XXXLOCK */
247 1.3 thorpej dreq->dreq_error = EINVAL;
248 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
249 1.3 thorpej /* XXXUNLOCK */
250 1.1 thorpej }
251 1.1 thorpej
252 1.1 thorpej dmover_done(dreq);
253 1.1 thorpej }
254 1.1 thorpej
255 1.6 briggs static void
256 1.6 briggs xor2(uint8_t *dst, uint8_t *src1, uint8_t *src2, int cnt)
257 1.6 briggs {
258 1.6 briggs
259 1.6 briggs while (cnt--)
260 1.6 briggs *dst++ = *src1++ ^ *src2++;
261 1.6 briggs }
262 1.6 briggs
263 1.6 briggs /*
264 1.6 briggs * swdmover_func_xor_process:
265 1.6 briggs *
266 1.6 briggs * Processing routine for the "xor" function.
267 1.6 briggs */
268 1.6 briggs static void
269 1.6 briggs swdmover_func_xor_process(struct dmover_request *dreq)
270 1.6 briggs {
271 1.6 briggs #define INBUF_L(x) dreq->dreq_inbuf[(x)].dmbuf_linear
272 1.6 briggs #define OUTBUF_L dreq->dreq_outbuf.dmbuf_linear
273 1.6 briggs
274 1.6 briggs uint32_t *dst32, *src32;
275 1.6 briggs uint8_t *dst8, *src8;
276 1.6 briggs int i, ninputs = dreq->dreq_assignment->das_algdesc->dad_ninputs;
277 1.6 briggs int aligned, len, nwords;
278 1.6 briggs
279 1.6 briggs /* XXX Currently, both buffers must be of same type. */
280 1.6 briggs if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) {
281 1.6 briggs /* XXXLOCK */
282 1.6 briggs dreq->dreq_error = EINVAL;
283 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
284 1.6 briggs /* XXXUNLOCK */
285 1.6 briggs goto done;
286 1.6 briggs }
287 1.6 briggs
288 1.6 briggs switch (dreq->dreq_outbuf_type) {
289 1.6 briggs case DMOVER_BUF_LINEAR:
290 1.6 briggs aligned = 1;
291 1.6 briggs if ((ulong) OUTBUF_L.l_addr & 0x3)
292 1.6 briggs aligned = 0;
293 1.7 briggs len = OUTBUF_L.l_len;
294 1.6 briggs for (i = 0 ; i < ninputs ; i++) {
295 1.6 briggs if (len != INBUF_L(i).l_len) {
296 1.6 briggs /* XXXLOCK */
297 1.6 briggs dreq->dreq_error = EINVAL;
298 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
299 1.6 briggs /* XXXUNLOCK */
300 1.6 briggs break;
301 1.6 briggs }
302 1.6 briggs if ((ulong) INBUF_L(i).l_addr & 0x3)
303 1.6 briggs aligned = 0;
304 1.6 briggs }
305 1.6 briggs if (aligned) {
306 1.6 briggs dst32 = (uint32_t *) OUTBUF_L.l_addr;
307 1.6 briggs nwords = len / 4;
308 1.6 briggs while (nwords--) {
309 1.6 briggs *dst32 = 0;
310 1.6 briggs for (i = 0 ; i < ninputs ; i++) {
311 1.6 briggs src32 = (uint32_t *) INBUF_L(i).l_addr;
312 1.6 briggs *dst32 ^= *src32;
313 1.6 briggs }
314 1.6 briggs dst32++;
315 1.6 briggs len -= 4;
316 1.6 briggs }
317 1.6 briggs }
318 1.6 briggs if (len) {
319 1.6 briggs dst8 = (uint8_t *) OUTBUF_L.l_addr;
320 1.6 briggs while (len--) {
321 1.6 briggs *dst8 = 0;
322 1.6 briggs for (i = 0 ; i < ninputs ; i++) {
323 1.6 briggs src8 = (uint8_t *) INBUF_L(i).l_addr;
324 1.6 briggs *dst8 ^= *src8;
325 1.6 briggs }
326 1.6 briggs dst8++;
327 1.6 briggs }
328 1.6 briggs }
329 1.8 perry
330 1.6 briggs break;
331 1.6 briggs
332 1.6 briggs case DMOVER_BUF_UIO:
333 1.6 briggs {
334 1.6 briggs struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio;
335 1.6 briggs struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
336 1.6 briggs struct uio *uio;
337 1.6 briggs char *cp, *dst;
338 1.6 briggs size_t count, buflen;
339 1.6 briggs int error;
340 1.6 briggs
341 1.6 briggs if (uio_in->uio_rw != UIO_WRITE ||
342 1.6 briggs uio_out->uio_rw != UIO_READ ||
343 1.6 briggs uio_in->uio_resid != uio_out->uio_resid) {
344 1.6 briggs /* XXXLOCK */
345 1.6 briggs dreq->dreq_error = EINVAL;
346 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
347 1.6 briggs /* XXXUNLOCK */
348 1.6 briggs break;
349 1.6 briggs }
350 1.6 briggs
351 1.6 briggs buflen = uio_in->uio_resid;
352 1.6 briggs if (buflen > 1024)
353 1.6 briggs buflen = 1024;
354 1.6 briggs cp = alloca(buflen);
355 1.6 briggs dst = alloca(buflen);
356 1.6 briggs
357 1.6 briggs /*
358 1.6 briggs * For each block, copy first input buffer into the destination
359 1.6 briggs * buffer and then read the rest, one by one, into a temporary
360 1.6 briggs * buffer and xor into the destination buffer. After all of
361 1.6 briggs * the inputs have been xor'd in, move the destination buffer
362 1.6 briggs * out and loop.
363 1.6 briggs */
364 1.6 briggs while ((count = uio_in->uio_resid) != 0) {
365 1.6 briggs if (count > buflen)
366 1.6 briggs count = buflen;
367 1.6 briggs error = uiomove(dst, count, uio_in);
368 1.6 briggs if (error) {
369 1.6 briggs /* XXXLOCK */
370 1.6 briggs dreq->dreq_error = error;
371 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
372 1.6 briggs /* XXXUNLOCK */
373 1.6 briggs break;
374 1.6 briggs }
375 1.6 briggs for (i=1 ; (i < ninputs) && (error == 0) ; i++) {
376 1.6 briggs uio = dreq->dreq_inbuf[i].dmbuf_uio;
377 1.6 briggs error = uiomove(cp, count, uio);
378 1.6 briggs if (error == 0) {
379 1.6 briggs xor2(dst, dst, cp, count);
380 1.6 briggs }
381 1.6 briggs }
382 1.6 briggs if (error == 0) {
383 1.6 briggs error = uiomove(dst, count, uio_out);
384 1.6 briggs } else {
385 1.6 briggs /* XXXLOCK */
386 1.6 briggs dreq->dreq_error = error;
387 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
388 1.6 briggs /* XXXUNLOCK */
389 1.6 briggs break;
390 1.6 briggs }
391 1.6 briggs }
392 1.6 briggs break;
393 1.6 briggs }
394 1.6 briggs
395 1.6 briggs default:
396 1.6 briggs /* XXXLOCK */
397 1.6 briggs dreq->dreq_error = EINVAL;
398 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
399 1.6 briggs /* XXXUNLOCK */
400 1.6 briggs }
401 1.6 briggs
402 1.6 briggs done:
403 1.6 briggs dmover_done(dreq);
404 1.6 briggs }
405 1.6 briggs
406 1.1 thorpej /*
407 1.1 thorpej * swdmover_func_copy_process:
408 1.1 thorpej *
409 1.1 thorpej * Processing routine for the "copy" function.
410 1.1 thorpej */
411 1.1 thorpej static void
412 1.1 thorpej swdmover_func_copy_process(struct dmover_request *dreq)
413 1.1 thorpej {
414 1.1 thorpej
415 1.4 thorpej /* XXX Currently, both buffers must be of same type. */
416 1.4 thorpej if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) {
417 1.4 thorpej /* XXXLOCK */
418 1.4 thorpej dreq->dreq_error = EINVAL;
419 1.4 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
420 1.4 thorpej /* XXXUNLOCK */
421 1.4 thorpej goto done;
422 1.4 thorpej }
423 1.4 thorpej
424 1.1 thorpej switch (dreq->dreq_outbuf_type) {
425 1.1 thorpej case DMOVER_BUF_LINEAR:
426 1.1 thorpej if (dreq->dreq_outbuf.dmbuf_linear.l_len !=
427 1.1 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_len) {
428 1.1 thorpej /* XXXLOCK */
429 1.1 thorpej dreq->dreq_error = EINVAL;
430 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
431 1.1 thorpej /* XXXUNLOCK */
432 1.1 thorpej break;
433 1.1 thorpej }
434 1.1 thorpej memcpy(dreq->dreq_outbuf.dmbuf_linear.l_addr,
435 1.1 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
436 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len);
437 1.1 thorpej break;
438 1.1 thorpej
439 1.1 thorpej case DMOVER_BUF_UIO:
440 1.1 thorpej {
441 1.1 thorpej struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio;
442 1.1 thorpej struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
443 1.1 thorpej char *cp;
444 1.1 thorpej size_t count, buflen;
445 1.1 thorpej int error;
446 1.1 thorpej
447 1.1 thorpej if (uio_in->uio_rw != UIO_WRITE ||
448 1.1 thorpej uio_out->uio_rw != UIO_READ ||
449 1.1 thorpej uio_in->uio_resid != uio_out->uio_resid) {
450 1.1 thorpej /* XXXLOCK */
451 1.1 thorpej dreq->dreq_error = EINVAL;
452 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
453 1.1 thorpej /* XXXUNLOCK */
454 1.1 thorpej break;
455 1.1 thorpej }
456 1.1 thorpej
457 1.1 thorpej buflen = uio_in->uio_resid;
458 1.1 thorpej if (buflen > 1024)
459 1.1 thorpej buflen = 1024;
460 1.1 thorpej cp = alloca(buflen);
461 1.1 thorpej
462 1.1 thorpej while ((count = uio_in->uio_resid) != 0) {
463 1.1 thorpej if (count > buflen)
464 1.1 thorpej count = buflen;
465 1.1 thorpej error = uiomove(cp, count, uio_in);
466 1.1 thorpej if (error == 0)
467 1.1 thorpej error = uiomove(cp, count, uio_out);
468 1.1 thorpej if (error) {
469 1.1 thorpej /* XXXLOCK */
470 1.1 thorpej dreq->dreq_error = error;
471 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
472 1.1 thorpej /* XXXUNLOCK */
473 1.1 thorpej break;
474 1.1 thorpej }
475 1.1 thorpej }
476 1.1 thorpej break;
477 1.1 thorpej }
478 1.3 thorpej
479 1.3 thorpej default:
480 1.3 thorpej /* XXXLOCK */
481 1.3 thorpej dreq->dreq_error = EINVAL;
482 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
483 1.3 thorpej /* XXXUNLOCK */
484 1.1 thorpej }
485 1.1 thorpej
486 1.4 thorpej done:
487 1.1 thorpej dmover_done(dreq);
488 1.1 thorpej }
489 1.1 thorpej
490 1.5 thorpej static const uint32_t iscsi_crc32c_table[256] = {
491 1.5 thorpej 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
492 1.5 thorpej 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
493 1.5 thorpej 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
494 1.5 thorpej 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
495 1.5 thorpej 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
496 1.5 thorpej 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
497 1.5 thorpej 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
498 1.5 thorpej 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
499 1.5 thorpej 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
500 1.5 thorpej 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
501 1.5 thorpej 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
502 1.5 thorpej 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
503 1.5 thorpej 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
504 1.5 thorpej 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
505 1.5 thorpej 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
506 1.5 thorpej 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
507 1.5 thorpej 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
508 1.5 thorpej 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
509 1.5 thorpej 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
510 1.5 thorpej 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
511 1.5 thorpej 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
512 1.5 thorpej 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
513 1.5 thorpej 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
514 1.5 thorpej 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
515 1.5 thorpej 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
516 1.5 thorpej 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
517 1.5 thorpej 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
518 1.5 thorpej 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
519 1.5 thorpej 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
520 1.5 thorpej 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
521 1.5 thorpej 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
522 1.5 thorpej 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
523 1.5 thorpej 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
524 1.5 thorpej 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
525 1.5 thorpej 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
526 1.5 thorpej 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
527 1.5 thorpej 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
528 1.5 thorpej 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
529 1.5 thorpej 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
530 1.5 thorpej 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
531 1.5 thorpej 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
532 1.5 thorpej 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
533 1.5 thorpej 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
534 1.5 thorpej 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
535 1.5 thorpej 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
536 1.5 thorpej 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
537 1.5 thorpej 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
538 1.5 thorpej 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
539 1.5 thorpej 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
540 1.5 thorpej 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
541 1.5 thorpej 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
542 1.5 thorpej 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
543 1.5 thorpej 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
544 1.5 thorpej 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
545 1.5 thorpej 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
546 1.5 thorpej 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
547 1.5 thorpej 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
548 1.5 thorpej 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
549 1.5 thorpej 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
550 1.5 thorpej 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
551 1.5 thorpej 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
552 1.5 thorpej 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
553 1.5 thorpej 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
554 1.5 thorpej 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
555 1.5 thorpej };
556 1.5 thorpej
557 1.5 thorpej static uint32_t
558 1.5 thorpej iscsi_crc32c(const uint8_t *buf, size_t len, uint32_t last)
559 1.5 thorpej {
560 1.5 thorpej uint32_t crc = 0xffffffffU ^ last;
561 1.5 thorpej
562 1.5 thorpej while (len--)
563 1.5 thorpej crc = iscsi_crc32c_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8);
564 1.5 thorpej
565 1.5 thorpej return (crc ^ 0xffffffffU);
566 1.5 thorpej }
567 1.5 thorpej
568 1.5 thorpej /*
569 1.5 thorpej * swdmover_func_iscsi_crc32c_process:
570 1.5 thorpej *
571 1.5 thorpej * Processing routine for the "iscsi-crc32c" function.
572 1.5 thorpej */
573 1.5 thorpej static void
574 1.5 thorpej swdmover_func_iscsi_crc32c_process(struct dmover_request *dreq)
575 1.5 thorpej {
576 1.5 thorpej uint32_t result;
577 1.5 thorpej
578 1.5 thorpej /* No output buffer; we use the immediate only. */
579 1.5 thorpej if (dreq->dreq_outbuf_type != DMOVER_BUF_NONE) {
580 1.5 thorpej /* XXXLOCK */
581 1.5 thorpej dreq->dreq_error = EINVAL;
582 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
583 1.5 thorpej /* XXXUNLOCK */
584 1.5 thorpej goto done;
585 1.5 thorpej }
586 1.5 thorpej
587 1.5 thorpej memcpy(&result, dreq->dreq_immediate, sizeof(result));
588 1.5 thorpej
589 1.5 thorpej switch (dreq->dreq_inbuf_type) {
590 1.5 thorpej case DMOVER_BUF_LINEAR:
591 1.5 thorpej result = iscsi_crc32c(dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
592 1.5 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_len, result);
593 1.5 thorpej break;
594 1.5 thorpej
595 1.5 thorpej case DMOVER_BUF_UIO:
596 1.5 thorpej {
597 1.5 thorpej struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
598 1.5 thorpej uint8_t *cp;
599 1.5 thorpej size_t count, buflen;
600 1.5 thorpej int error;
601 1.5 thorpej
602 1.5 thorpej if (uio_in->uio_rw != UIO_WRITE) {
603 1.5 thorpej /* XXXLOCK */
604 1.5 thorpej dreq->dreq_error = EINVAL;
605 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
606 1.5 thorpej /* XXXUNLOCK */
607 1.5 thorpej goto done;
608 1.5 thorpej }
609 1.5 thorpej
610 1.5 thorpej buflen = uio_in->uio_resid;
611 1.5 thorpej if (buflen > 1024)
612 1.5 thorpej buflen = 1024;
613 1.5 thorpej cp = alloca(buflen);
614 1.5 thorpej
615 1.5 thorpej while ((count = uio_in->uio_resid) != 0) {
616 1.5 thorpej if (count > buflen)
617 1.5 thorpej count = buflen;
618 1.5 thorpej error = uiomove(cp, count, uio_in);
619 1.5 thorpej if (error) {
620 1.5 thorpej /* XXXLOCK */
621 1.5 thorpej dreq->dreq_error = error;
622 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
623 1.5 thorpej /* XXXUNLOCK */
624 1.5 thorpej goto done;
625 1.5 thorpej } else
626 1.5 thorpej result = iscsi_crc32c(cp, count, result);
627 1.5 thorpej }
628 1.5 thorpej break;
629 1.5 thorpej }
630 1.5 thorpej
631 1.5 thorpej default:
632 1.5 thorpej /* XXXLOCK */
633 1.5 thorpej dreq->dreq_error = EINVAL;
634 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
635 1.5 thorpej /* XXXUNLOCK */
636 1.5 thorpej goto done;
637 1.5 thorpej }
638 1.5 thorpej
639 1.5 thorpej memcpy(dreq->dreq_immediate, &result, sizeof(result));
640 1.5 thorpej done:
641 1.5 thorpej dmover_done(dreq);
642 1.5 thorpej }
643 1.5 thorpej
644 1.1 thorpej static struct swdmover_function swdmover_func_zero = {
645 1.1 thorpej swdmover_func_zero_process
646 1.1 thorpej };
647 1.1 thorpej
648 1.1 thorpej static struct swdmover_function swdmover_func_fill8 = {
649 1.1 thorpej swdmover_func_fill8_process
650 1.1 thorpej };
651 1.1 thorpej
652 1.5 thorpej static struct swdmover_function swdmover_func_copy = {
653 1.1 thorpej swdmover_func_copy_process
654 1.1 thorpej };
655 1.1 thorpej
656 1.6 briggs static struct swdmover_function swdmover_func_xor = {
657 1.6 briggs swdmover_func_xor_process
658 1.6 briggs };
659 1.6 briggs
660 1.5 thorpej static struct swdmover_function swdmover_func_iscsi_crc32c = {
661 1.5 thorpej swdmover_func_iscsi_crc32c_process
662 1.5 thorpej };
663 1.5 thorpej
664 1.1 thorpej const struct dmover_algdesc swdmover_algdescs[] = {
665 1.6 briggs {
666 1.6 briggs DMOVER_FUNC_XOR2,
667 1.6 briggs &swdmover_func_xor,
668 1.6 briggs 2
669 1.6 briggs },
670 1.6 briggs {
671 1.6 briggs DMOVER_FUNC_XOR3,
672 1.6 briggs &swdmover_func_xor,
673 1.6 briggs 3
674 1.6 briggs },
675 1.6 briggs {
676 1.6 briggs DMOVER_FUNC_XOR4,
677 1.6 briggs &swdmover_func_xor,
678 1.6 briggs 4
679 1.6 briggs },
680 1.6 briggs {
681 1.6 briggs DMOVER_FUNC_XOR5,
682 1.6 briggs &swdmover_func_xor,
683 1.6 briggs 5
684 1.6 briggs },
685 1.6 briggs {
686 1.6 briggs DMOVER_FUNC_XOR6,
687 1.6 briggs &swdmover_func_xor,
688 1.6 briggs 6
689 1.6 briggs },
690 1.6 briggs {
691 1.6 briggs DMOVER_FUNC_XOR7,
692 1.6 briggs &swdmover_func_xor,
693 1.6 briggs 7
694 1.6 briggs },
695 1.6 briggs {
696 1.6 briggs DMOVER_FUNC_XOR8,
697 1.6 briggs &swdmover_func_xor,
698 1.6 briggs 8
699 1.6 briggs },
700 1.1 thorpej {
701 1.1 thorpej DMOVER_FUNC_ZERO,
702 1.1 thorpej &swdmover_func_zero,
703 1.1 thorpej 0
704 1.1 thorpej },
705 1.1 thorpej {
706 1.1 thorpej DMOVER_FUNC_FILL8,
707 1.1 thorpej &swdmover_func_fill8,
708 1.1 thorpej 0
709 1.1 thorpej },
710 1.1 thorpej {
711 1.1 thorpej DMOVER_FUNC_COPY,
712 1.1 thorpej &swdmover_func_copy,
713 1.1 thorpej 1
714 1.5 thorpej },
715 1.5 thorpej {
716 1.5 thorpej DMOVER_FUNC_ISCSI_CRC32C,
717 1.5 thorpej &swdmover_func_iscsi_crc32c,
718 1.5 thorpej 1,
719 1.1 thorpej },
720 1.1 thorpej };
721 1.1 thorpej #define SWDMOVER_ALGDESC_COUNT \
722 1.1 thorpej (sizeof(swdmover_algdescs) / sizeof(swdmover_algdescs[0]))
723 1.1 thorpej
724 1.1 thorpej /*
725 1.1 thorpej * swdmoverattach:
726 1.1 thorpej *
727 1.1 thorpej * Pesudo-device attach routine.
728 1.1 thorpej */
729 1.1 thorpej void
730 1.1 thorpej swdmoverattach(int count)
731 1.1 thorpej {
732 1.10 ad int error;
733 1.1 thorpej
734 1.1 thorpej swdmover_backend.dmb_name = "swdmover";
735 1.1 thorpej swdmover_backend.dmb_speed = 1; /* XXX */
736 1.1 thorpej swdmover_backend.dmb_cookie = NULL;
737 1.1 thorpej swdmover_backend.dmb_algdescs = swdmover_algdescs;
738 1.1 thorpej swdmover_backend.dmb_nalgdescs = SWDMOVER_ALGDESC_COUNT;
739 1.1 thorpej swdmover_backend.dmb_process = swdmover_process;
740 1.1 thorpej
741 1.10 ad error = kthread_create(PRI_NONE, 0, NULL, swdmover_thread,
742 1.11 he &swdmover_backend, &swdmover_lwp, "swdmover");
743 1.10 ad if (error)
744 1.10 ad printf("WARNING: unable to create swdmover thread, "
745 1.10 ad "error = %d\n", error);
746 1.1 thorpej
747 1.1 thorpej /* XXX Should only register this when kthread creation succeeds. */
748 1.1 thorpej dmover_backend_register(&swdmover_backend);
749 1.1 thorpej }
750