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