swdmover.c revision 1.13
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
63struct swdmover_function {
64	void	(*sdf_process)(struct dmover_request *);
65};
66
67static struct dmover_backend swdmover_backend;
68static struct lwp *swdmover_lwp;
69static int swdmover_cv;
70
71/*
72 * swdmover_process:
73 *
74 *	Dmover back-end entry point.
75 */
76static void
77swdmover_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 */
99static void
100swdmover_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 */
137static void
138swdmover_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 */
198static void
199swdmover_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
255static void
256xor2(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 */
268static void
269swdmover_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 */
411static void
412swdmover_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
490static 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
557static uint32_t
558iscsi_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 */
573static void
574swdmover_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
644static struct swdmover_function swdmover_func_zero = {
645	swdmover_func_zero_process
646};
647
648static struct swdmover_function swdmover_func_fill8 = {
649	swdmover_func_fill8_process
650};
651
652static struct swdmover_function swdmover_func_copy = {
653	swdmover_func_copy_process
654};
655
656static struct swdmover_function swdmover_func_xor = {
657	swdmover_func_xor_process
658};
659
660static struct swdmover_function swdmover_func_iscsi_crc32c = {
661	swdmover_func_iscsi_crc32c_process
662};
663
664const 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 */
729void
730swdmoverattach(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