swdmover.c revision 1.10
1/*	$NetBSD: swdmover.c,v 1.10 2007/07/09 21:00:32 ad 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.10 2007/07/09 21:00:32 ad 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
62struct swdmover_function {
63	void	(*sdf_process)(struct dmover_request *);
64};
65
66static struct dmover_backend swdmover_backend;
67static struct proc *swdmover_proc;
68static int swdmover_cv;
69
70void	swdmoverattach(int);
71
72/*
73 * swdmover_process:
74 *
75 *	Dmover back-end entry point.
76 */
77static void
78swdmover_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 */
100static void
101swdmover_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 */
138static void
139swdmover_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 */
199static void
200swdmover_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
256static void
257xor2(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 */
269static void
270swdmover_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 */
412static void
413swdmover_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
491static 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
558static uint32_t
559iscsi_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 */
574static void
575swdmover_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
645static struct swdmover_function swdmover_func_zero = {
646	swdmover_func_zero_process
647};
648
649static struct swdmover_function swdmover_func_fill8 = {
650	swdmover_func_fill8_process
651};
652
653static struct swdmover_function swdmover_func_copy = {
654	swdmover_func_copy_process
655};
656
657static struct swdmover_function swdmover_func_xor = {
658	swdmover_func_xor_process
659};
660
661static struct swdmover_function swdmover_func_iscsi_crc32c = {
662	swdmover_func_iscsi_crc32c_process
663};
664
665const 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 */
730void
731swdmoverattach(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	    arg, &swdmover_proc, "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