1*863d66edSchristos /* $NetBSD: swdmover.c,v 1.14 2017/01/07 21:11:14 christos Exp $ */
25d06c0e8Sthorpej
35d06c0e8Sthorpej /*
4b41675bcSthorpej * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
55d06c0e8Sthorpej * All rights reserved.
65d06c0e8Sthorpej *
75d06c0e8Sthorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc.
85d06c0e8Sthorpej *
95d06c0e8Sthorpej * Redistribution and use in source and binary forms, with or without
105d06c0e8Sthorpej * modification, are permitted provided that the following conditions
115d06c0e8Sthorpej * are met:
125d06c0e8Sthorpej * 1. Redistributions of source code must retain the above copyright
135d06c0e8Sthorpej * notice, this list of conditions and the following disclaimer.
145d06c0e8Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
155d06c0e8Sthorpej * notice, this list of conditions and the following disclaimer in the
165d06c0e8Sthorpej * documentation and/or other materials provided with the distribution.
175d06c0e8Sthorpej * 3. All advertising materials mentioning features or use of this software
185d06c0e8Sthorpej * must display the following acknowledgement:
195d06c0e8Sthorpej * This product includes software developed for the NetBSD Project by
205d06c0e8Sthorpej * Wasabi Systems, Inc.
215d06c0e8Sthorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse
225d06c0e8Sthorpej * or promote products derived from this software without specific prior
235d06c0e8Sthorpej * written permission.
245d06c0e8Sthorpej *
255d06c0e8Sthorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
265d06c0e8Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
275d06c0e8Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
285d06c0e8Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
295d06c0e8Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
305d06c0e8Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
315d06c0e8Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
325d06c0e8Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
335d06c0e8Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
345d06c0e8Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
355d06c0e8Sthorpej * POSSIBILITY OF SUCH DAMAGE.
365d06c0e8Sthorpej */
375d06c0e8Sthorpej
385d06c0e8Sthorpej /*
395d06c0e8Sthorpej * swdmover.c: Software back-end providing the dmover functions
405d06c0e8Sthorpej * mentioned in dmover(9).
415d06c0e8Sthorpej *
425d06c0e8Sthorpej * This module provides a fallback for cases where no hardware
435d06c0e8Sthorpej * data movers are present in a system, and also serves an an
445d06c0e8Sthorpej * example of how to write a dmover back-end.
455d06c0e8Sthorpej *
465d06c0e8Sthorpej * Note that even through the software dmover doesn't require
475d06c0e8Sthorpej * interrupts to be blocked, we block them anyway to demonstrate
485d06c0e8Sthorpej * the locking protocol.
495d06c0e8Sthorpej */
505d06c0e8Sthorpej
515d06c0e8Sthorpej #include <sys/cdefs.h>
52*863d66edSchristos __KERNEL_RCSID(0, "$NetBSD: swdmover.c,v 1.14 2017/01/07 21:11:14 christos Exp $");
535d06c0e8Sthorpej
545d06c0e8Sthorpej #include <sys/param.h>
555d06c0e8Sthorpej #include <sys/kthread.h>
565d06c0e8Sthorpej #include <sys/systm.h>
575d06c0e8Sthorpej #include <sys/uio.h>
585d06c0e8Sthorpej
595d06c0e8Sthorpej #include <dev/dmover/dmovervar.h>
605d06c0e8Sthorpej
61e7ae23fdSchristos #include "ioconf.h"
62e7ae23fdSchristos
635d06c0e8Sthorpej struct swdmover_function {
645d06c0e8Sthorpej void (*sdf_process)(struct dmover_request *);
655d06c0e8Sthorpej };
665d06c0e8Sthorpej
675d06c0e8Sthorpej static struct dmover_backend swdmover_backend;
68cdcf88b0She static struct lwp *swdmover_lwp;
695d06c0e8Sthorpej static int swdmover_cv;
705d06c0e8Sthorpej
715d06c0e8Sthorpej /*
725d06c0e8Sthorpej * swdmover_process:
735d06c0e8Sthorpej *
745d06c0e8Sthorpej * Dmover back-end entry point.
755d06c0e8Sthorpej */
765d06c0e8Sthorpej static void
swdmover_process(struct dmover_backend * dmb)775d06c0e8Sthorpej swdmover_process(struct dmover_backend *dmb)
785d06c0e8Sthorpej {
795d06c0e8Sthorpej int s;
805d06c0e8Sthorpej
815d06c0e8Sthorpej /*
825d06c0e8Sthorpej * Just wake up the processing thread. This will allow
835d06c0e8Sthorpej * requests to linger on the middle-end's queue so that
845d06c0e8Sthorpej * they can be cancelled, if need-be.
855d06c0e8Sthorpej */
865d06c0e8Sthorpej s = splbio();
875d06c0e8Sthorpej /* XXXLOCK */
885d06c0e8Sthorpej if (TAILQ_EMPTY(&dmb->dmb_pendreqs) == 0)
895d06c0e8Sthorpej wakeup(&swdmover_cv);
905d06c0e8Sthorpej /* XXXUNLOCK */
915d06c0e8Sthorpej splx(s);
925d06c0e8Sthorpej }
935d06c0e8Sthorpej
945d06c0e8Sthorpej /*
955d06c0e8Sthorpej * swdmover_thread:
965d06c0e8Sthorpej *
975d06c0e8Sthorpej * Request processing thread.
985d06c0e8Sthorpej */
995d06c0e8Sthorpej static void
swdmover_thread(void * arg)1005d06c0e8Sthorpej swdmover_thread(void *arg)
1015d06c0e8Sthorpej {
1025d06c0e8Sthorpej struct dmover_backend *dmb = arg;
1035d06c0e8Sthorpej struct dmover_request *dreq;
1045d06c0e8Sthorpej struct swdmover_function *sdf;
1055d06c0e8Sthorpej int s;
1065d06c0e8Sthorpej
1075d06c0e8Sthorpej s = splbio();
1085d06c0e8Sthorpej /* XXXLOCK */
1095d06c0e8Sthorpej
1105d06c0e8Sthorpej for (;;) {
1115d06c0e8Sthorpej dreq = TAILQ_FIRST(&dmb->dmb_pendreqs);
1125d06c0e8Sthorpej if (dreq == NULL) {
1135d06c0e8Sthorpej /* XXXUNLOCK */
1145d06c0e8Sthorpej (void) tsleep(&swdmover_cv, PRIBIO, "swdmvr", 0);
1155d06c0e8Sthorpej continue;
1165d06c0e8Sthorpej }
1175d06c0e8Sthorpej
1185d06c0e8Sthorpej dmover_backend_remque(dmb, dreq);
1195d06c0e8Sthorpej dreq->dreq_flags |= DMOVER_REQ_RUNNING;
1205d06c0e8Sthorpej
1215d06c0e8Sthorpej /* XXXUNLOCK */
1225d06c0e8Sthorpej splx(s);
1235d06c0e8Sthorpej
1245d06c0e8Sthorpej sdf = dreq->dreq_assignment->das_algdesc->dad_data;
1255d06c0e8Sthorpej (*sdf->sdf_process)(dreq);
1265d06c0e8Sthorpej
1275d06c0e8Sthorpej s = splbio();
1285d06c0e8Sthorpej /* XXXLOCK */
1295d06c0e8Sthorpej }
1305d06c0e8Sthorpej }
1315d06c0e8Sthorpej
1325d06c0e8Sthorpej /*
1335d06c0e8Sthorpej * swdmover_func_zero_process:
1345d06c0e8Sthorpej *
1355d06c0e8Sthorpej * Processing routine for the "zero" function.
1365d06c0e8Sthorpej */
1375d06c0e8Sthorpej static void
swdmover_func_zero_process(struct dmover_request * dreq)1385d06c0e8Sthorpej swdmover_func_zero_process(struct dmover_request *dreq)
1395d06c0e8Sthorpej {
1405d06c0e8Sthorpej
1415d06c0e8Sthorpej switch (dreq->dreq_outbuf_type) {
1425d06c0e8Sthorpej case DMOVER_BUF_LINEAR:
1435d06c0e8Sthorpej memset(dreq->dreq_outbuf.dmbuf_linear.l_addr, 0,
1445d06c0e8Sthorpej dreq->dreq_outbuf.dmbuf_linear.l_len);
1455d06c0e8Sthorpej break;
1465d06c0e8Sthorpej
1475d06c0e8Sthorpej case DMOVER_BUF_UIO:
1485d06c0e8Sthorpej {
1495d06c0e8Sthorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio;
150*863d66edSchristos char cp[1024];
1515d06c0e8Sthorpej size_t count, buflen;
1525d06c0e8Sthorpej int error;
1535d06c0e8Sthorpej
1545d06c0e8Sthorpej if (uio->uio_rw != UIO_READ) {
1555d06c0e8Sthorpej /* XXXLOCK */
1565d06c0e8Sthorpej dreq->dreq_error = EINVAL;
1575d06c0e8Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
1585d06c0e8Sthorpej /* XXXUNLOCK */
1595d06c0e8Sthorpej break;
1605d06c0e8Sthorpej }
1615d06c0e8Sthorpej
1625d06c0e8Sthorpej buflen = uio->uio_resid;
163*863d66edSchristos if (buflen > sizeof(cp))
164*863d66edSchristos buflen = sizeof(cp);
1655d06c0e8Sthorpej memset(cp, 0, buflen);
1665d06c0e8Sthorpej
1675d06c0e8Sthorpej while ((count = uio->uio_resid) != 0) {
1685d06c0e8Sthorpej if (count > buflen)
1695d06c0e8Sthorpej count = buflen;
1705d06c0e8Sthorpej error = uiomove(cp, count, uio);
1715d06c0e8Sthorpej if (error) {
1725d06c0e8Sthorpej /* XXXLOCK */
1735d06c0e8Sthorpej dreq->dreq_error = error;
1745d06c0e8Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
1755d06c0e8Sthorpej /* XXXUNLOCK */
1765d06c0e8Sthorpej break;
1775d06c0e8Sthorpej }
1785d06c0e8Sthorpej }
1795d06c0e8Sthorpej break;
1805d06c0e8Sthorpej }
18190044065Sthorpej
18290044065Sthorpej default:
18390044065Sthorpej /* XXXLOCK */
18490044065Sthorpej dreq->dreq_error = EINVAL;
18590044065Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
18690044065Sthorpej /* XXXUNLOCK */
1875d06c0e8Sthorpej }
1885d06c0e8Sthorpej
1895d06c0e8Sthorpej dmover_done(dreq);
1905d06c0e8Sthorpej }
1915d06c0e8Sthorpej
1925d06c0e8Sthorpej /*
1935d06c0e8Sthorpej * swdmover_func_fill8_process:
1945d06c0e8Sthorpej *
1955d06c0e8Sthorpej * Processing routine for the "fill8" function.
1965d06c0e8Sthorpej */
1975d06c0e8Sthorpej static void
swdmover_func_fill8_process(struct dmover_request * dreq)1985d06c0e8Sthorpej swdmover_func_fill8_process(struct dmover_request *dreq)
1995d06c0e8Sthorpej {
2005d06c0e8Sthorpej
2015d06c0e8Sthorpej switch (dreq->dreq_outbuf_type) {
2025d06c0e8Sthorpej case DMOVER_BUF_LINEAR:
2035d06c0e8Sthorpej memset(dreq->dreq_outbuf.dmbuf_linear.l_addr,
2045d06c0e8Sthorpej dreq->dreq_immediate[0],
2055d06c0e8Sthorpej dreq->dreq_outbuf.dmbuf_linear.l_len);
2065d06c0e8Sthorpej break;
2075d06c0e8Sthorpej
2085d06c0e8Sthorpej case DMOVER_BUF_UIO:
2095d06c0e8Sthorpej {
2105d06c0e8Sthorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio;
211*863d66edSchristos char cp[1024];
2125d06c0e8Sthorpej size_t count, buflen;
2135d06c0e8Sthorpej int error;
2145d06c0e8Sthorpej
2155d06c0e8Sthorpej if (uio->uio_rw != UIO_READ) {
2165d06c0e8Sthorpej /* XXXLOCK */
2175d06c0e8Sthorpej dreq->dreq_error = EINVAL;
2185d06c0e8Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
2195d06c0e8Sthorpej /* XXXUNLOCK */
2205d06c0e8Sthorpej break;
2215d06c0e8Sthorpej }
2225d06c0e8Sthorpej
2235d06c0e8Sthorpej buflen = uio->uio_resid;
224*863d66edSchristos if (buflen > sizeof(cp))
225*863d66edSchristos buflen = sizeof(cp);
2265d06c0e8Sthorpej memset(cp, dreq->dreq_immediate[0], buflen);
2275d06c0e8Sthorpej
2285d06c0e8Sthorpej while ((count = uio->uio_resid) != 0) {
2295d06c0e8Sthorpej if (count > buflen)
2305d06c0e8Sthorpej count = buflen;
2315d06c0e8Sthorpej error = uiomove(cp, count, uio);
2325d06c0e8Sthorpej if (error) {
2335d06c0e8Sthorpej /* XXXLOCK */
2345d06c0e8Sthorpej dreq->dreq_error = error;
2355d06c0e8Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
2365d06c0e8Sthorpej /* XXXUNLOCK */
2375d06c0e8Sthorpej break;
2385d06c0e8Sthorpej }
2395d06c0e8Sthorpej }
2405d06c0e8Sthorpej break;
2415d06c0e8Sthorpej }
24290044065Sthorpej
24390044065Sthorpej default:
24490044065Sthorpej /* XXXLOCK */
24590044065Sthorpej dreq->dreq_error = EINVAL;
24690044065Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
24790044065Sthorpej /* XXXUNLOCK */
2485d06c0e8Sthorpej }
2495d06c0e8Sthorpej
2505d06c0e8Sthorpej dmover_done(dreq);
2515d06c0e8Sthorpej }
2525d06c0e8Sthorpej
2536d7027eeSbriggs static void
xor2(uint8_t * dst,uint8_t * src1,uint8_t * src2,int cnt)2546d7027eeSbriggs xor2(uint8_t *dst, uint8_t *src1, uint8_t *src2, int cnt)
2556d7027eeSbriggs {
2566d7027eeSbriggs
2576d7027eeSbriggs while (cnt--)
2586d7027eeSbriggs *dst++ = *src1++ ^ *src2++;
2596d7027eeSbriggs }
2606d7027eeSbriggs
2616d7027eeSbriggs /*
2626d7027eeSbriggs * swdmover_func_xor_process:
2636d7027eeSbriggs *
2646d7027eeSbriggs * Processing routine for the "xor" function.
2656d7027eeSbriggs */
2666d7027eeSbriggs static void
swdmover_func_xor_process(struct dmover_request * dreq)2676d7027eeSbriggs swdmover_func_xor_process(struct dmover_request *dreq)
2686d7027eeSbriggs {
2696d7027eeSbriggs #define INBUF_L(x) dreq->dreq_inbuf[(x)].dmbuf_linear
2706d7027eeSbriggs #define OUTBUF_L dreq->dreq_outbuf.dmbuf_linear
2716d7027eeSbriggs
2726d7027eeSbriggs uint32_t *dst32, *src32;
2736d7027eeSbriggs uint8_t *dst8, *src8;
2746d7027eeSbriggs int i, ninputs = dreq->dreq_assignment->das_algdesc->dad_ninputs;
2756d7027eeSbriggs int aligned, len, nwords;
2766d7027eeSbriggs
2776d7027eeSbriggs /* XXX Currently, both buffers must be of same type. */
2786d7027eeSbriggs if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) {
2796d7027eeSbriggs /* XXXLOCK */
2806d7027eeSbriggs dreq->dreq_error = EINVAL;
2816d7027eeSbriggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
2826d7027eeSbriggs /* XXXUNLOCK */
2836d7027eeSbriggs goto done;
2846d7027eeSbriggs }
2856d7027eeSbriggs
2866d7027eeSbriggs switch (dreq->dreq_outbuf_type) {
2876d7027eeSbriggs case DMOVER_BUF_LINEAR:
2886d7027eeSbriggs aligned = 1;
2896d7027eeSbriggs if ((ulong) OUTBUF_L.l_addr & 0x3)
2906d7027eeSbriggs aligned = 0;
291cad1dd99Sbriggs len = OUTBUF_L.l_len;
2926d7027eeSbriggs for (i = 0 ; i < ninputs ; i++) {
2936d7027eeSbriggs if (len != INBUF_L(i).l_len) {
2946d7027eeSbriggs /* XXXLOCK */
2956d7027eeSbriggs dreq->dreq_error = EINVAL;
2966d7027eeSbriggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
2976d7027eeSbriggs /* XXXUNLOCK */
2986d7027eeSbriggs break;
2996d7027eeSbriggs }
3006d7027eeSbriggs if ((ulong) INBUF_L(i).l_addr & 0x3)
3016d7027eeSbriggs aligned = 0;
3026d7027eeSbriggs }
3036d7027eeSbriggs if (aligned) {
3046d7027eeSbriggs dst32 = (uint32_t *) OUTBUF_L.l_addr;
3056d7027eeSbriggs nwords = len / 4;
3066d7027eeSbriggs while (nwords--) {
3076d7027eeSbriggs *dst32 = 0;
3086d7027eeSbriggs for (i = 0 ; i < ninputs ; i++) {
3096d7027eeSbriggs src32 = (uint32_t *) INBUF_L(i).l_addr;
3106d7027eeSbriggs *dst32 ^= *src32;
3116d7027eeSbriggs }
3126d7027eeSbriggs dst32++;
3136d7027eeSbriggs len -= 4;
3146d7027eeSbriggs }
3156d7027eeSbriggs }
3166d7027eeSbriggs if (len) {
3176d7027eeSbriggs dst8 = (uint8_t *) OUTBUF_L.l_addr;
3186d7027eeSbriggs while (len--) {
3196d7027eeSbriggs *dst8 = 0;
3206d7027eeSbriggs for (i = 0 ; i < ninputs ; i++) {
3216d7027eeSbriggs src8 = (uint8_t *) INBUF_L(i).l_addr;
3226d7027eeSbriggs *dst8 ^= *src8;
3236d7027eeSbriggs }
3246d7027eeSbriggs dst8++;
3256d7027eeSbriggs }
3266d7027eeSbriggs }
3276d7027eeSbriggs
3286d7027eeSbriggs break;
3296d7027eeSbriggs
3306d7027eeSbriggs case DMOVER_BUF_UIO:
3316d7027eeSbriggs {
3326d7027eeSbriggs struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio;
3336d7027eeSbriggs struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
3346d7027eeSbriggs struct uio *uio;
335*863d66edSchristos char cp[1024], dst[1024];
3366d7027eeSbriggs size_t count, buflen;
3376d7027eeSbriggs int error;
3386d7027eeSbriggs
3396d7027eeSbriggs if (uio_in->uio_rw != UIO_WRITE ||
3406d7027eeSbriggs uio_out->uio_rw != UIO_READ ||
3416d7027eeSbriggs uio_in->uio_resid != uio_out->uio_resid) {
3426d7027eeSbriggs /* XXXLOCK */
3436d7027eeSbriggs dreq->dreq_error = EINVAL;
3446d7027eeSbriggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
3456d7027eeSbriggs /* XXXUNLOCK */
3466d7027eeSbriggs break;
3476d7027eeSbriggs }
3486d7027eeSbriggs
3496d7027eeSbriggs buflen = uio_in->uio_resid;
350*863d66edSchristos if (buflen > sizeof(cp))
351*863d66edSchristos buflen = sizeof(cp);
3526d7027eeSbriggs
3536d7027eeSbriggs /*
3546d7027eeSbriggs * For each block, copy first input buffer into the destination
3556d7027eeSbriggs * buffer and then read the rest, one by one, into a temporary
3566d7027eeSbriggs * buffer and xor into the destination buffer. After all of
3576d7027eeSbriggs * the inputs have been xor'd in, move the destination buffer
3586d7027eeSbriggs * out and loop.
3596d7027eeSbriggs */
3606d7027eeSbriggs while ((count = uio_in->uio_resid) != 0) {
3616d7027eeSbriggs if (count > buflen)
3626d7027eeSbriggs count = buflen;
3636d7027eeSbriggs error = uiomove(dst, count, uio_in);
3646d7027eeSbriggs if (error) {
3656d7027eeSbriggs /* XXXLOCK */
3666d7027eeSbriggs dreq->dreq_error = error;
3676d7027eeSbriggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
3686d7027eeSbriggs /* XXXUNLOCK */
3696d7027eeSbriggs break;
3706d7027eeSbriggs }
3716d7027eeSbriggs for (i=1 ; (i < ninputs) && (error == 0) ; i++) {
3726d7027eeSbriggs uio = dreq->dreq_inbuf[i].dmbuf_uio;
3736d7027eeSbriggs error = uiomove(cp, count, uio);
3746d7027eeSbriggs if (error == 0) {
3756d7027eeSbriggs xor2(dst, dst, cp, count);
3766d7027eeSbriggs }
3776d7027eeSbriggs }
3786d7027eeSbriggs if (error == 0) {
3796d7027eeSbriggs error = uiomove(dst, count, uio_out);
3806d7027eeSbriggs } else {
3816d7027eeSbriggs /* XXXLOCK */
3826d7027eeSbriggs dreq->dreq_error = error;
3836d7027eeSbriggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
3846d7027eeSbriggs /* XXXUNLOCK */
3856d7027eeSbriggs break;
3866d7027eeSbriggs }
3876d7027eeSbriggs }
3886d7027eeSbriggs break;
3896d7027eeSbriggs }
3906d7027eeSbriggs
3916d7027eeSbriggs default:
3926d7027eeSbriggs /* XXXLOCK */
3936d7027eeSbriggs dreq->dreq_error = EINVAL;
3946d7027eeSbriggs dreq->dreq_flags |= DMOVER_REQ_ERROR;
3956d7027eeSbriggs /* XXXUNLOCK */
3966d7027eeSbriggs }
3976d7027eeSbriggs
3986d7027eeSbriggs done:
3996d7027eeSbriggs dmover_done(dreq);
4006d7027eeSbriggs }
4016d7027eeSbriggs
4025d06c0e8Sthorpej /*
4035d06c0e8Sthorpej * swdmover_func_copy_process:
4045d06c0e8Sthorpej *
4055d06c0e8Sthorpej * Processing routine for the "copy" function.
4065d06c0e8Sthorpej */
4075d06c0e8Sthorpej static void
swdmover_func_copy_process(struct dmover_request * dreq)4085d06c0e8Sthorpej swdmover_func_copy_process(struct dmover_request *dreq)
4095d06c0e8Sthorpej {
4105d06c0e8Sthorpej
411a5722408Sthorpej /* XXX Currently, both buffers must be of same type. */
412a5722408Sthorpej if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) {
413a5722408Sthorpej /* XXXLOCK */
414a5722408Sthorpej dreq->dreq_error = EINVAL;
415a5722408Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
416a5722408Sthorpej /* XXXUNLOCK */
417a5722408Sthorpej goto done;
418a5722408Sthorpej }
419a5722408Sthorpej
4205d06c0e8Sthorpej switch (dreq->dreq_outbuf_type) {
4215d06c0e8Sthorpej case DMOVER_BUF_LINEAR:
4225d06c0e8Sthorpej if (dreq->dreq_outbuf.dmbuf_linear.l_len !=
4235d06c0e8Sthorpej dreq->dreq_inbuf[0].dmbuf_linear.l_len) {
4245d06c0e8Sthorpej /* XXXLOCK */
4255d06c0e8Sthorpej dreq->dreq_error = EINVAL;
4265d06c0e8Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
4275d06c0e8Sthorpej /* XXXUNLOCK */
4285d06c0e8Sthorpej break;
4295d06c0e8Sthorpej }
4305d06c0e8Sthorpej memcpy(dreq->dreq_outbuf.dmbuf_linear.l_addr,
4315d06c0e8Sthorpej dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
4325d06c0e8Sthorpej dreq->dreq_outbuf.dmbuf_linear.l_len);
4335d06c0e8Sthorpej break;
4345d06c0e8Sthorpej
4355d06c0e8Sthorpej case DMOVER_BUF_UIO:
4365d06c0e8Sthorpej {
4375d06c0e8Sthorpej struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio;
4385d06c0e8Sthorpej struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
439*863d66edSchristos char cp[1024];
4405d06c0e8Sthorpej size_t count, buflen;
4415d06c0e8Sthorpej int error;
4425d06c0e8Sthorpej
4435d06c0e8Sthorpej if (uio_in->uio_rw != UIO_WRITE ||
4445d06c0e8Sthorpej uio_out->uio_rw != UIO_READ ||
4455d06c0e8Sthorpej uio_in->uio_resid != uio_out->uio_resid) {
4465d06c0e8Sthorpej /* XXXLOCK */
4475d06c0e8Sthorpej dreq->dreq_error = EINVAL;
4485d06c0e8Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
4495d06c0e8Sthorpej /* XXXUNLOCK */
4505d06c0e8Sthorpej break;
4515d06c0e8Sthorpej }
4525d06c0e8Sthorpej
4535d06c0e8Sthorpej buflen = uio_in->uio_resid;
454*863d66edSchristos if (buflen > sizeof(cp))
455*863d66edSchristos buflen = sizeof(cp);
4565d06c0e8Sthorpej
4575d06c0e8Sthorpej while ((count = uio_in->uio_resid) != 0) {
4585d06c0e8Sthorpej if (count > buflen)
4595d06c0e8Sthorpej count = buflen;
4605d06c0e8Sthorpej error = uiomove(cp, count, uio_in);
4615d06c0e8Sthorpej if (error == 0)
4625d06c0e8Sthorpej error = uiomove(cp, count, uio_out);
4635d06c0e8Sthorpej if (error) {
4645d06c0e8Sthorpej /* XXXLOCK */
4655d06c0e8Sthorpej dreq->dreq_error = error;
4665d06c0e8Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
4675d06c0e8Sthorpej /* XXXUNLOCK */
4685d06c0e8Sthorpej break;
4695d06c0e8Sthorpej }
4705d06c0e8Sthorpej }
4715d06c0e8Sthorpej break;
4725d06c0e8Sthorpej }
47390044065Sthorpej
47490044065Sthorpej default:
47590044065Sthorpej /* XXXLOCK */
47690044065Sthorpej dreq->dreq_error = EINVAL;
47790044065Sthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
47890044065Sthorpej /* XXXUNLOCK */
4795d06c0e8Sthorpej }
4805d06c0e8Sthorpej
481a5722408Sthorpej done:
4825d06c0e8Sthorpej dmover_done(dreq);
4835d06c0e8Sthorpej }
4845d06c0e8Sthorpej
485b41675bcSthorpej static const uint32_t iscsi_crc32c_table[256] = {
486b41675bcSthorpej 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
487b41675bcSthorpej 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
488b41675bcSthorpej 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
489b41675bcSthorpej 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
490b41675bcSthorpej 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
491b41675bcSthorpej 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
492b41675bcSthorpej 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
493b41675bcSthorpej 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
494b41675bcSthorpej 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
495b41675bcSthorpej 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
496b41675bcSthorpej 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
497b41675bcSthorpej 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
498b41675bcSthorpej 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
499b41675bcSthorpej 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
500b41675bcSthorpej 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
501b41675bcSthorpej 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
502b41675bcSthorpej 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
503b41675bcSthorpej 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
504b41675bcSthorpej 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
505b41675bcSthorpej 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
506b41675bcSthorpej 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
507b41675bcSthorpej 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
508b41675bcSthorpej 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
509b41675bcSthorpej 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
510b41675bcSthorpej 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
511b41675bcSthorpej 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
512b41675bcSthorpej 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
513b41675bcSthorpej 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
514b41675bcSthorpej 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
515b41675bcSthorpej 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
516b41675bcSthorpej 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
517b41675bcSthorpej 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
518b41675bcSthorpej 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
519b41675bcSthorpej 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
520b41675bcSthorpej 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
521b41675bcSthorpej 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
522b41675bcSthorpej 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
523b41675bcSthorpej 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
524b41675bcSthorpej 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
525b41675bcSthorpej 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
526b41675bcSthorpej 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
527b41675bcSthorpej 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
528b41675bcSthorpej 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
529b41675bcSthorpej 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
530b41675bcSthorpej 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
531b41675bcSthorpej 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
532b41675bcSthorpej 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
533b41675bcSthorpej 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
534b41675bcSthorpej 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
535b41675bcSthorpej 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
536b41675bcSthorpej 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
537b41675bcSthorpej 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
538b41675bcSthorpej 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
539b41675bcSthorpej 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
540b41675bcSthorpej 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
541b41675bcSthorpej 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
542b41675bcSthorpej 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
543b41675bcSthorpej 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
544b41675bcSthorpej 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
545b41675bcSthorpej 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
546b41675bcSthorpej 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
547b41675bcSthorpej 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
548b41675bcSthorpej 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
549b41675bcSthorpej 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
550b41675bcSthorpej };
551b41675bcSthorpej
552b41675bcSthorpej static uint32_t
iscsi_crc32c(const uint8_t * buf,size_t len,uint32_t last)553b41675bcSthorpej iscsi_crc32c(const uint8_t *buf, size_t len, uint32_t last)
554b41675bcSthorpej {
555b41675bcSthorpej uint32_t crc = 0xffffffffU ^ last;
556b41675bcSthorpej
557b41675bcSthorpej while (len--)
558b41675bcSthorpej crc = iscsi_crc32c_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8);
559b41675bcSthorpej
560b41675bcSthorpej return (crc ^ 0xffffffffU);
561b41675bcSthorpej }
562b41675bcSthorpej
563b41675bcSthorpej /*
564b41675bcSthorpej * swdmover_func_iscsi_crc32c_process:
565b41675bcSthorpej *
566b41675bcSthorpej * Processing routine for the "iscsi-crc32c" function.
567b41675bcSthorpej */
568b41675bcSthorpej static void
swdmover_func_iscsi_crc32c_process(struct dmover_request * dreq)569b41675bcSthorpej swdmover_func_iscsi_crc32c_process(struct dmover_request *dreq)
570b41675bcSthorpej {
571b41675bcSthorpej uint32_t result;
572b41675bcSthorpej
573b41675bcSthorpej /* No output buffer; we use the immediate only. */
574b41675bcSthorpej if (dreq->dreq_outbuf_type != DMOVER_BUF_NONE) {
575b41675bcSthorpej /* XXXLOCK */
576b41675bcSthorpej dreq->dreq_error = EINVAL;
577b41675bcSthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
578b41675bcSthorpej /* XXXUNLOCK */
579b41675bcSthorpej goto done;
580b41675bcSthorpej }
581b41675bcSthorpej
582b41675bcSthorpej memcpy(&result, dreq->dreq_immediate, sizeof(result));
583b41675bcSthorpej
584b41675bcSthorpej switch (dreq->dreq_inbuf_type) {
585b41675bcSthorpej case DMOVER_BUF_LINEAR:
586b41675bcSthorpej result = iscsi_crc32c(dreq->dreq_inbuf[0].dmbuf_linear.l_addr,
587b41675bcSthorpej dreq->dreq_inbuf[0].dmbuf_linear.l_len, result);
588b41675bcSthorpej break;
589b41675bcSthorpej
590b41675bcSthorpej case DMOVER_BUF_UIO:
591b41675bcSthorpej {
592b41675bcSthorpej struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio;
593*863d66edSchristos uint8_t cp[1024];
594b41675bcSthorpej size_t count, buflen;
595b41675bcSthorpej int error;
596b41675bcSthorpej
597b41675bcSthorpej if (uio_in->uio_rw != UIO_WRITE) {
598b41675bcSthorpej /* XXXLOCK */
599b41675bcSthorpej dreq->dreq_error = EINVAL;
600b41675bcSthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
601b41675bcSthorpej /* XXXUNLOCK */
602b41675bcSthorpej goto done;
603b41675bcSthorpej }
604b41675bcSthorpej
605b41675bcSthorpej buflen = uio_in->uio_resid;
606*863d66edSchristos if (buflen > sizeof(cp))
607*863d66edSchristos buflen = sizeof(cp);
608b41675bcSthorpej
609b41675bcSthorpej while ((count = uio_in->uio_resid) != 0) {
610b41675bcSthorpej if (count > buflen)
611b41675bcSthorpej count = buflen;
612b41675bcSthorpej error = uiomove(cp, count, uio_in);
613b41675bcSthorpej if (error) {
614b41675bcSthorpej /* XXXLOCK */
615b41675bcSthorpej dreq->dreq_error = error;
616b41675bcSthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
617b41675bcSthorpej /* XXXUNLOCK */
618b41675bcSthorpej goto done;
619b41675bcSthorpej } else
620b41675bcSthorpej result = iscsi_crc32c(cp, count, result);
621b41675bcSthorpej }
622b41675bcSthorpej break;
623b41675bcSthorpej }
624b41675bcSthorpej
625b41675bcSthorpej default:
626b41675bcSthorpej /* XXXLOCK */
627b41675bcSthorpej dreq->dreq_error = EINVAL;
628b41675bcSthorpej dreq->dreq_flags |= DMOVER_REQ_ERROR;
629b41675bcSthorpej /* XXXUNLOCK */
630b41675bcSthorpej goto done;
631b41675bcSthorpej }
632b41675bcSthorpej
633b41675bcSthorpej memcpy(dreq->dreq_immediate, &result, sizeof(result));
634b41675bcSthorpej done:
635b41675bcSthorpej dmover_done(dreq);
636b41675bcSthorpej }
637b41675bcSthorpej
6385d06c0e8Sthorpej static struct swdmover_function swdmover_func_zero = {
6395d06c0e8Sthorpej swdmover_func_zero_process
6405d06c0e8Sthorpej };
6415d06c0e8Sthorpej
6425d06c0e8Sthorpej static struct swdmover_function swdmover_func_fill8 = {
6435d06c0e8Sthorpej swdmover_func_fill8_process
6445d06c0e8Sthorpej };
6455d06c0e8Sthorpej
646b41675bcSthorpej static struct swdmover_function swdmover_func_copy = {
6475d06c0e8Sthorpej swdmover_func_copy_process
6485d06c0e8Sthorpej };
6495d06c0e8Sthorpej
6506d7027eeSbriggs static struct swdmover_function swdmover_func_xor = {
6516d7027eeSbriggs swdmover_func_xor_process
6526d7027eeSbriggs };
6536d7027eeSbriggs
654b41675bcSthorpej static struct swdmover_function swdmover_func_iscsi_crc32c = {
655b41675bcSthorpej swdmover_func_iscsi_crc32c_process
656b41675bcSthorpej };
657b41675bcSthorpej
6585d06c0e8Sthorpej const struct dmover_algdesc swdmover_algdescs[] = {
6595d06c0e8Sthorpej {
6606d7027eeSbriggs DMOVER_FUNC_XOR2,
6616d7027eeSbriggs &swdmover_func_xor,
6626d7027eeSbriggs 2
6636d7027eeSbriggs },
6646d7027eeSbriggs {
6656d7027eeSbriggs DMOVER_FUNC_XOR3,
6666d7027eeSbriggs &swdmover_func_xor,
6676d7027eeSbriggs 3
6686d7027eeSbriggs },
6696d7027eeSbriggs {
6706d7027eeSbriggs DMOVER_FUNC_XOR4,
6716d7027eeSbriggs &swdmover_func_xor,
6726d7027eeSbriggs 4
6736d7027eeSbriggs },
6746d7027eeSbriggs {
6756d7027eeSbriggs DMOVER_FUNC_XOR5,
6766d7027eeSbriggs &swdmover_func_xor,
6776d7027eeSbriggs 5
6786d7027eeSbriggs },
6796d7027eeSbriggs {
6806d7027eeSbriggs DMOVER_FUNC_XOR6,
6816d7027eeSbriggs &swdmover_func_xor,
6826d7027eeSbriggs 6
6836d7027eeSbriggs },
6846d7027eeSbriggs {
6856d7027eeSbriggs DMOVER_FUNC_XOR7,
6866d7027eeSbriggs &swdmover_func_xor,
6876d7027eeSbriggs 7
6886d7027eeSbriggs },
6896d7027eeSbriggs {
6906d7027eeSbriggs DMOVER_FUNC_XOR8,
6916d7027eeSbriggs &swdmover_func_xor,
6926d7027eeSbriggs 8
6936d7027eeSbriggs },
6946d7027eeSbriggs {
6955d06c0e8Sthorpej DMOVER_FUNC_ZERO,
6965d06c0e8Sthorpej &swdmover_func_zero,
6975d06c0e8Sthorpej 0
6985d06c0e8Sthorpej },
6995d06c0e8Sthorpej {
7005d06c0e8Sthorpej DMOVER_FUNC_FILL8,
7015d06c0e8Sthorpej &swdmover_func_fill8,
7025d06c0e8Sthorpej 0
7035d06c0e8Sthorpej },
7045d06c0e8Sthorpej {
7055d06c0e8Sthorpej DMOVER_FUNC_COPY,
7065d06c0e8Sthorpej &swdmover_func_copy,
7075d06c0e8Sthorpej 1
7085d06c0e8Sthorpej },
709b41675bcSthorpej {
710b41675bcSthorpej DMOVER_FUNC_ISCSI_CRC32C,
711b41675bcSthorpej &swdmover_func_iscsi_crc32c,
712b41675bcSthorpej 1,
713b41675bcSthorpej },
7145d06c0e8Sthorpej };
7155d06c0e8Sthorpej #define SWDMOVER_ALGDESC_COUNT \
7165d06c0e8Sthorpej (sizeof(swdmover_algdescs) / sizeof(swdmover_algdescs[0]))
7175d06c0e8Sthorpej
7185d06c0e8Sthorpej /*
7195d06c0e8Sthorpej * swdmoverattach:
7205d06c0e8Sthorpej *
7215d06c0e8Sthorpej * Pesudo-device attach routine.
7225d06c0e8Sthorpej */
7235d06c0e8Sthorpej void
swdmoverattach(int count)7245d06c0e8Sthorpej swdmoverattach(int count)
7255d06c0e8Sthorpej {
72688ab7da9Sad int error;
7275d06c0e8Sthorpej
7285d06c0e8Sthorpej swdmover_backend.dmb_name = "swdmover";
7295d06c0e8Sthorpej swdmover_backend.dmb_speed = 1; /* XXX */
7305d06c0e8Sthorpej swdmover_backend.dmb_cookie = NULL;
7315d06c0e8Sthorpej swdmover_backend.dmb_algdescs = swdmover_algdescs;
7325d06c0e8Sthorpej swdmover_backend.dmb_nalgdescs = SWDMOVER_ALGDESC_COUNT;
7335d06c0e8Sthorpej swdmover_backend.dmb_process = swdmover_process;
7345d06c0e8Sthorpej
73588ab7da9Sad error = kthread_create(PRI_NONE, 0, NULL, swdmover_thread,
736cdcf88b0She &swdmover_backend, &swdmover_lwp, "swdmover");
73788ab7da9Sad if (error)
73888ab7da9Sad printf("WARNING: unable to create swdmover thread, "
73988ab7da9Sad "error = %d\n", error);
7405d06c0e8Sthorpej
7415d06c0e8Sthorpej /* XXX Should only register this when kthread creation succeeds. */
7425d06c0e8Sthorpej dmover_backend_register(&swdmover_backend);
7435d06c0e8Sthorpej }
744