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