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