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