swdmover.c revision 1.5 1 /* $NetBSD: swdmover.c,v 1.5 2003/07/19 02:05:35 thorpej 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.5 2003/07/19 02:05:35 thorpej 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
62 struct swdmover_function {
63 void (*sdf_process)(struct dmover_request *);
64 };
65
66 static struct dmover_backend swdmover_backend;
67 static struct proc *swdmover_proc;
68 static int swdmover_cv;
69
70 void swdmoverattach(int);
71
72 /*
73 * swdmover_process:
74 *
75 * Dmover back-end entry point.
76 */
77 static void
78 swdmover_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 */
100 static void
101 swdmover_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 */
138 static void
139 swdmover_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 */
199 static void
200 swdmover_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
256 /*
257 * swdmover_func_copy_process:
258 *
259 * Processing routine for the "copy" function.
260 */
261 static void
262 swdmover_func_copy_process(struct dmover_request *dreq)
263 {
264
265 /* XXX Currently, both buffers must be of same type. */
266 if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) {
267 /* XXXLOCK */
268 dreq->dreq_error = EINVAL;
269 dreq->dreq_flags |= DMOVER_REQ_ERROR;
270 /* XXXUNLOCK */
271 goto done;
272 }
273
274 switch (dreq->dreq_outbuf_type) {
275 case DMOVER_BUF_LINEAR:
276 if (dreq->dreq_outbuf.dmbuf_linear.l_len !=
277 dreq->dreq_inbuf[0].dmbuf_linear.l_len) {
278 /* XXXLOCK */
279 dreq->dreq_error = EINVAL;
280 dreq->dreq_flags |= DMOVER_REQ_ERROR;
281 /* XXXUNLOCK */
282 break;
283 }
284 memcpy(dreq->dreq_outbuf.dmbuf_linear.l_addr,
285 dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
286 dreq->dreq_outbuf.dmbuf_linear.l_len);
287 break;
288
289 case DMOVER_BUF_UIO:
290 {
291 struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio;
292 struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
293 char *cp;
294 size_t count, buflen;
295 int error;
296
297 if (uio_in->uio_rw != UIO_WRITE ||
298 uio_out->uio_rw != UIO_READ ||
299 uio_in->uio_resid != uio_out->uio_resid) {
300 /* XXXLOCK */
301 dreq->dreq_error = EINVAL;
302 dreq->dreq_flags |= DMOVER_REQ_ERROR;
303 /* XXXUNLOCK */
304 break;
305 }
306
307 buflen = uio_in->uio_resid;
308 if (buflen > 1024)
309 buflen = 1024;
310 cp = alloca(buflen);
311
312 while ((count = uio_in->uio_resid) != 0) {
313 if (count > buflen)
314 count = buflen;
315 error = uiomove(cp, count, uio_in);
316 if (error == 0)
317 error = uiomove(cp, count, uio_out);
318 if (error) {
319 /* XXXLOCK */
320 dreq->dreq_error = error;
321 dreq->dreq_flags |= DMOVER_REQ_ERROR;
322 /* XXXUNLOCK */
323 break;
324 }
325 }
326 break;
327 }
328
329 default:
330 /* XXXLOCK */
331 dreq->dreq_error = EINVAL;
332 dreq->dreq_flags |= DMOVER_REQ_ERROR;
333 /* XXXUNLOCK */
334 }
335
336 done:
337 dmover_done(dreq);
338 }
339
340 static const uint32_t iscsi_crc32c_table[256] = {
341 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
342 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
343 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
344 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
345 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
346 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
347 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
348 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
349 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
350 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
351 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
352 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
353 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
354 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
355 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
356 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
357 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
358 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
359 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
360 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
361 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
362 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
363 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
364 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
365 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
366 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
367 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
368 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
369 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
370 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
371 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
372 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
373 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
374 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
375 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
376 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
377 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
378 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
379 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
380 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
381 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
382 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
383 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
384 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
385 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
386 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
387 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
388 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
389 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
390 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
391 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
392 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
393 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
394 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
395 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
396 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
397 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
398 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
399 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
400 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
401 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
402 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
403 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
404 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
405 };
406
407 static uint32_t
408 iscsi_crc32c(const uint8_t *buf, size_t len, uint32_t last)
409 {
410 uint32_t crc = 0xffffffffU ^ last;
411
412 while (len--)
413 crc = iscsi_crc32c_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8);
414
415 return (crc ^ 0xffffffffU);
416 }
417
418 /*
419 * swdmover_func_iscsi_crc32c_process:
420 *
421 * Processing routine for the "iscsi-crc32c" function.
422 */
423 static void
424 swdmover_func_iscsi_crc32c_process(struct dmover_request *dreq)
425 {
426 uint32_t result;
427
428 /* No output buffer; we use the immediate only. */
429 if (dreq->dreq_outbuf_type != DMOVER_BUF_NONE) {
430 /* XXXLOCK */
431 dreq->dreq_error = EINVAL;
432 dreq->dreq_flags |= DMOVER_REQ_ERROR;
433 /* XXXUNLOCK */
434 goto done;
435 }
436
437 memcpy(&result, dreq->dreq_immediate, sizeof(result));
438
439 switch (dreq->dreq_inbuf_type) {
440 case DMOVER_BUF_LINEAR:
441 result = iscsi_crc32c(dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
442 dreq->dreq_inbuf[0].dmbuf_linear.l_len, result);
443 break;
444
445 case DMOVER_BUF_UIO:
446 {
447 struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
448 uint8_t *cp;
449 size_t count, buflen;
450 int error;
451
452 if (uio_in->uio_rw != UIO_WRITE) {
453 /* XXXLOCK */
454 dreq->dreq_error = EINVAL;
455 dreq->dreq_flags |= DMOVER_REQ_ERROR;
456 /* XXXUNLOCK */
457 goto done;
458 }
459
460 buflen = uio_in->uio_resid;
461 if (buflen > 1024)
462 buflen = 1024;
463 cp = alloca(buflen);
464
465 while ((count = uio_in->uio_resid) != 0) {
466 if (count > buflen)
467 count = buflen;
468 error = uiomove(cp, count, uio_in);
469 if (error) {
470 /* XXXLOCK */
471 dreq->dreq_error = error;
472 dreq->dreq_flags |= DMOVER_REQ_ERROR;
473 /* XXXUNLOCK */
474 goto done;
475 } else
476 result = iscsi_crc32c(cp, count, result);
477 }
478 break;
479 }
480
481 default:
482 /* XXXLOCK */
483 dreq->dreq_error = EINVAL;
484 dreq->dreq_flags |= DMOVER_REQ_ERROR;
485 /* XXXUNLOCK */
486 goto done;
487 }
488
489 memcpy(dreq->dreq_immediate, &result, sizeof(result));
490 done:
491 dmover_done(dreq);
492 }
493
494 static struct swdmover_function swdmover_func_zero = {
495 swdmover_func_zero_process
496 };
497
498 static struct swdmover_function swdmover_func_fill8 = {
499 swdmover_func_fill8_process
500 };
501
502 static struct swdmover_function swdmover_func_copy = {
503 swdmover_func_copy_process
504 };
505
506 static struct swdmover_function swdmover_func_iscsi_crc32c = {
507 swdmover_func_iscsi_crc32c_process
508 };
509
510 const struct dmover_algdesc swdmover_algdescs[] = {
511 {
512 DMOVER_FUNC_ZERO,
513 &swdmover_func_zero,
514 0
515 },
516 {
517 DMOVER_FUNC_FILL8,
518 &swdmover_func_fill8,
519 0
520 },
521 {
522 DMOVER_FUNC_COPY,
523 &swdmover_func_copy,
524 1
525 },
526 {
527 DMOVER_FUNC_ISCSI_CRC32C,
528 &swdmover_func_iscsi_crc32c,
529 1,
530 },
531 };
532 #define SWDMOVER_ALGDESC_COUNT \
533 (sizeof(swdmover_algdescs) / sizeof(swdmover_algdescs[0]))
534
535 /*
536 * swdmover_create_thread:
537 *
538 * Actually create the swdmover processing thread.
539 */
540 static void
541 swdmover_create_thread(void *arg)
542 {
543 int error;
544
545 error = kthread_create1(swdmover_thread, arg, &swdmover_proc,
546 "swdmover");
547 if (error)
548 printf("WARNING: unable to create swdmover thread, "
549 "error = %d\n", error);
550 }
551
552 /*
553 * swdmoverattach:
554 *
555 * Pesudo-device attach routine.
556 */
557 void
558 swdmoverattach(int count)
559 {
560
561 swdmover_backend.dmb_name = "swdmover";
562 swdmover_backend.dmb_speed = 1; /* XXX */
563 swdmover_backend.dmb_cookie = NULL;
564 swdmover_backend.dmb_algdescs = swdmover_algdescs;
565 swdmover_backend.dmb_nalgdescs = SWDMOVER_ALGDESC_COUNT;
566 swdmover_backend.dmb_process = swdmover_process;
567
568 kthread_create(swdmover_create_thread, &swdmover_backend);
569
570 /* XXX Should only register this when kthread creation succeeds. */
571 dmover_backend_register(&swdmover_backend);
572 }
573