1 1.14 christos /* $NetBSD: swdmover.c,v 1.14 2017/01/07 21:11:14 christos Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.5 thorpej * Copyright (c) 2002, 2003 Wasabi Systems, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 1.1 thorpej * 9 1.1 thorpej * Redistribution and use in source and binary forms, with or without 10 1.1 thorpej * modification, are permitted provided that the following conditions 11 1.1 thorpej * are met: 12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer. 14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 16 1.1 thorpej * documentation and/or other materials provided with the distribution. 17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 18 1.1 thorpej * must display the following acknowledgement: 19 1.1 thorpej * This product includes software developed for the NetBSD Project by 20 1.1 thorpej * Wasabi Systems, Inc. 21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 thorpej * or promote products derived from this software without specific prior 23 1.1 thorpej * written permission. 24 1.1 thorpej * 25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 36 1.1 thorpej */ 37 1.1 thorpej 38 1.1 thorpej /* 39 1.1 thorpej * swdmover.c: Software back-end providing the dmover functions 40 1.1 thorpej * mentioned in dmover(9). 41 1.1 thorpej * 42 1.1 thorpej * This module provides a fallback for cases where no hardware 43 1.1 thorpej * data movers are present in a system, and also serves an an 44 1.1 thorpej * example of how to write a dmover back-end. 45 1.1 thorpej * 46 1.1 thorpej * Note that even through the software dmover doesn't require 47 1.1 thorpej * interrupts to be blocked, we block them anyway to demonstrate 48 1.1 thorpej * the locking protocol. 49 1.1 thorpej */ 50 1.1 thorpej 51 1.1 thorpej #include <sys/cdefs.h> 52 1.14 christos __KERNEL_RCSID(0, "$NetBSD: swdmover.c,v 1.14 2017/01/07 21:11:14 christos Exp $"); 53 1.1 thorpej 54 1.1 thorpej #include <sys/param.h> 55 1.1 thorpej #include <sys/kthread.h> 56 1.1 thorpej #include <sys/systm.h> 57 1.1 thorpej #include <sys/uio.h> 58 1.1 thorpej 59 1.1 thorpej #include <dev/dmover/dmovervar.h> 60 1.1 thorpej 61 1.13 christos #include "ioconf.h" 62 1.13 christos 63 1.1 thorpej struct swdmover_function { 64 1.1 thorpej void (*sdf_process)(struct dmover_request *); 65 1.1 thorpej }; 66 1.1 thorpej 67 1.1 thorpej static struct dmover_backend swdmover_backend; 68 1.11 he static struct lwp *swdmover_lwp; 69 1.1 thorpej static int swdmover_cv; 70 1.1 thorpej 71 1.1 thorpej /* 72 1.1 thorpej * swdmover_process: 73 1.1 thorpej * 74 1.1 thorpej * Dmover back-end entry point. 75 1.1 thorpej */ 76 1.1 thorpej static void 77 1.1 thorpej swdmover_process(struct dmover_backend *dmb) 78 1.1 thorpej { 79 1.1 thorpej int s; 80 1.1 thorpej 81 1.1 thorpej /* 82 1.1 thorpej * Just wake up the processing thread. This will allow 83 1.1 thorpej * requests to linger on the middle-end's queue so that 84 1.1 thorpej * they can be cancelled, if need-be. 85 1.1 thorpej */ 86 1.1 thorpej s = splbio(); 87 1.1 thorpej /* XXXLOCK */ 88 1.1 thorpej if (TAILQ_EMPTY(&dmb->dmb_pendreqs) == 0) 89 1.1 thorpej wakeup(&swdmover_cv); 90 1.1 thorpej /* XXXUNLOCK */ 91 1.1 thorpej splx(s); 92 1.1 thorpej } 93 1.1 thorpej 94 1.1 thorpej /* 95 1.1 thorpej * swdmover_thread: 96 1.1 thorpej * 97 1.1 thorpej * Request processing thread. 98 1.1 thorpej */ 99 1.1 thorpej static void 100 1.1 thorpej swdmover_thread(void *arg) 101 1.1 thorpej { 102 1.1 thorpej struct dmover_backend *dmb = arg; 103 1.1 thorpej struct dmover_request *dreq; 104 1.1 thorpej struct swdmover_function *sdf; 105 1.1 thorpej int s; 106 1.1 thorpej 107 1.1 thorpej s = splbio(); 108 1.1 thorpej /* XXXLOCK */ 109 1.1 thorpej 110 1.1 thorpej for (;;) { 111 1.1 thorpej dreq = TAILQ_FIRST(&dmb->dmb_pendreqs); 112 1.1 thorpej if (dreq == NULL) { 113 1.1 thorpej /* XXXUNLOCK */ 114 1.1 thorpej (void) tsleep(&swdmover_cv, PRIBIO, "swdmvr", 0); 115 1.1 thorpej continue; 116 1.1 thorpej } 117 1.1 thorpej 118 1.1 thorpej dmover_backend_remque(dmb, dreq); 119 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_RUNNING; 120 1.1 thorpej 121 1.1 thorpej /* XXXUNLOCK */ 122 1.1 thorpej splx(s); 123 1.1 thorpej 124 1.1 thorpej sdf = dreq->dreq_assignment->das_algdesc->dad_data; 125 1.1 thorpej (*sdf->sdf_process)(dreq); 126 1.1 thorpej 127 1.1 thorpej s = splbio(); 128 1.1 thorpej /* XXXLOCK */ 129 1.1 thorpej } 130 1.1 thorpej } 131 1.1 thorpej 132 1.1 thorpej /* 133 1.1 thorpej * swdmover_func_zero_process: 134 1.1 thorpej * 135 1.1 thorpej * Processing routine for the "zero" function. 136 1.1 thorpej */ 137 1.1 thorpej static void 138 1.1 thorpej swdmover_func_zero_process(struct dmover_request *dreq) 139 1.1 thorpej { 140 1.1 thorpej 141 1.1 thorpej switch (dreq->dreq_outbuf_type) { 142 1.1 thorpej case DMOVER_BUF_LINEAR: 143 1.1 thorpej memset(dreq->dreq_outbuf.dmbuf_linear.l_addr, 0, 144 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len); 145 1.1 thorpej break; 146 1.1 thorpej 147 1.1 thorpej case DMOVER_BUF_UIO: 148 1.1 thorpej { 149 1.1 thorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio; 150 1.14 christos char cp[1024]; 151 1.1 thorpej size_t count, buflen; 152 1.1 thorpej int error; 153 1.1 thorpej 154 1.1 thorpej if (uio->uio_rw != UIO_READ) { 155 1.1 thorpej /* XXXLOCK */ 156 1.1 thorpej dreq->dreq_error = EINVAL; 157 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 158 1.1 thorpej /* XXXUNLOCK */ 159 1.1 thorpej break; 160 1.1 thorpej } 161 1.1 thorpej 162 1.1 thorpej buflen = uio->uio_resid; 163 1.14 christos if (buflen > sizeof(cp)) 164 1.14 christos buflen = sizeof(cp); 165 1.1 thorpej memset(cp, 0, buflen); 166 1.1 thorpej 167 1.1 thorpej while ((count = uio->uio_resid) != 0) { 168 1.1 thorpej if (count > buflen) 169 1.1 thorpej count = buflen; 170 1.1 thorpej error = uiomove(cp, count, uio); 171 1.1 thorpej if (error) { 172 1.1 thorpej /* XXXLOCK */ 173 1.1 thorpej dreq->dreq_error = error; 174 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 175 1.1 thorpej /* XXXUNLOCK */ 176 1.1 thorpej break; 177 1.1 thorpej } 178 1.1 thorpej } 179 1.1 thorpej break; 180 1.1 thorpej } 181 1.3 thorpej 182 1.3 thorpej default: 183 1.3 thorpej /* XXXLOCK */ 184 1.3 thorpej dreq->dreq_error = EINVAL; 185 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 186 1.3 thorpej /* XXXUNLOCK */ 187 1.1 thorpej } 188 1.1 thorpej 189 1.1 thorpej dmover_done(dreq); 190 1.1 thorpej } 191 1.1 thorpej 192 1.1 thorpej /* 193 1.1 thorpej * swdmover_func_fill8_process: 194 1.1 thorpej * 195 1.1 thorpej * Processing routine for the "fill8" function. 196 1.1 thorpej */ 197 1.1 thorpej static void 198 1.1 thorpej swdmover_func_fill8_process(struct dmover_request *dreq) 199 1.1 thorpej { 200 1.1 thorpej 201 1.1 thorpej switch (dreq->dreq_outbuf_type) { 202 1.1 thorpej case DMOVER_BUF_LINEAR: 203 1.1 thorpej memset(dreq->dreq_outbuf.dmbuf_linear.l_addr, 204 1.1 thorpej dreq->dreq_immediate[0], 205 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len); 206 1.1 thorpej break; 207 1.1 thorpej 208 1.1 thorpej case DMOVER_BUF_UIO: 209 1.1 thorpej { 210 1.1 thorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio; 211 1.14 christos char cp[1024]; 212 1.1 thorpej size_t count, buflen; 213 1.1 thorpej int error; 214 1.1 thorpej 215 1.1 thorpej if (uio->uio_rw != UIO_READ) { 216 1.1 thorpej /* XXXLOCK */ 217 1.1 thorpej dreq->dreq_error = EINVAL; 218 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 219 1.1 thorpej /* XXXUNLOCK */ 220 1.1 thorpej break; 221 1.1 thorpej } 222 1.1 thorpej 223 1.1 thorpej buflen = uio->uio_resid; 224 1.14 christos if (buflen > sizeof(cp)) 225 1.14 christos buflen = sizeof(cp); 226 1.1 thorpej memset(cp, dreq->dreq_immediate[0], buflen); 227 1.1 thorpej 228 1.1 thorpej while ((count = uio->uio_resid) != 0) { 229 1.1 thorpej if (count > buflen) 230 1.1 thorpej count = buflen; 231 1.1 thorpej error = uiomove(cp, count, uio); 232 1.1 thorpej if (error) { 233 1.1 thorpej /* XXXLOCK */ 234 1.1 thorpej dreq->dreq_error = error; 235 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 236 1.1 thorpej /* XXXUNLOCK */ 237 1.1 thorpej break; 238 1.1 thorpej } 239 1.1 thorpej } 240 1.1 thorpej break; 241 1.1 thorpej } 242 1.3 thorpej 243 1.3 thorpej default: 244 1.3 thorpej /* XXXLOCK */ 245 1.3 thorpej dreq->dreq_error = EINVAL; 246 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 247 1.3 thorpej /* XXXUNLOCK */ 248 1.1 thorpej } 249 1.1 thorpej 250 1.1 thorpej dmover_done(dreq); 251 1.1 thorpej } 252 1.1 thorpej 253 1.6 briggs static void 254 1.6 briggs xor2(uint8_t *dst, uint8_t *src1, uint8_t *src2, int cnt) 255 1.6 briggs { 256 1.6 briggs 257 1.6 briggs while (cnt--) 258 1.6 briggs *dst++ = *src1++ ^ *src2++; 259 1.6 briggs } 260 1.6 briggs 261 1.6 briggs /* 262 1.6 briggs * swdmover_func_xor_process: 263 1.6 briggs * 264 1.6 briggs * Processing routine for the "xor" function. 265 1.6 briggs */ 266 1.6 briggs static void 267 1.6 briggs swdmover_func_xor_process(struct dmover_request *dreq) 268 1.6 briggs { 269 1.6 briggs #define INBUF_L(x) dreq->dreq_inbuf[(x)].dmbuf_linear 270 1.6 briggs #define OUTBUF_L dreq->dreq_outbuf.dmbuf_linear 271 1.6 briggs 272 1.6 briggs uint32_t *dst32, *src32; 273 1.6 briggs uint8_t *dst8, *src8; 274 1.6 briggs int i, ninputs = dreq->dreq_assignment->das_algdesc->dad_ninputs; 275 1.6 briggs int aligned, len, nwords; 276 1.6 briggs 277 1.6 briggs /* XXX Currently, both buffers must be of same type. */ 278 1.6 briggs if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) { 279 1.6 briggs /* XXXLOCK */ 280 1.6 briggs dreq->dreq_error = EINVAL; 281 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR; 282 1.6 briggs /* XXXUNLOCK */ 283 1.6 briggs goto done; 284 1.6 briggs } 285 1.6 briggs 286 1.6 briggs switch (dreq->dreq_outbuf_type) { 287 1.6 briggs case DMOVER_BUF_LINEAR: 288 1.6 briggs aligned = 1; 289 1.6 briggs if ((ulong) OUTBUF_L.l_addr & 0x3) 290 1.6 briggs aligned = 0; 291 1.7 briggs len = OUTBUF_L.l_len; 292 1.6 briggs for (i = 0 ; i < ninputs ; i++) { 293 1.6 briggs if (len != INBUF_L(i).l_len) { 294 1.6 briggs /* XXXLOCK */ 295 1.6 briggs dreq->dreq_error = EINVAL; 296 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR; 297 1.6 briggs /* XXXUNLOCK */ 298 1.6 briggs break; 299 1.6 briggs } 300 1.6 briggs if ((ulong) INBUF_L(i).l_addr & 0x3) 301 1.6 briggs aligned = 0; 302 1.6 briggs } 303 1.6 briggs if (aligned) { 304 1.6 briggs dst32 = (uint32_t *) OUTBUF_L.l_addr; 305 1.6 briggs nwords = len / 4; 306 1.6 briggs while (nwords--) { 307 1.6 briggs *dst32 = 0; 308 1.6 briggs for (i = 0 ; i < ninputs ; i++) { 309 1.6 briggs src32 = (uint32_t *) INBUF_L(i).l_addr; 310 1.6 briggs *dst32 ^= *src32; 311 1.6 briggs } 312 1.6 briggs dst32++; 313 1.6 briggs len -= 4; 314 1.6 briggs } 315 1.6 briggs } 316 1.6 briggs if (len) { 317 1.6 briggs dst8 = (uint8_t *) OUTBUF_L.l_addr; 318 1.6 briggs while (len--) { 319 1.6 briggs *dst8 = 0; 320 1.6 briggs for (i = 0 ; i < ninputs ; i++) { 321 1.6 briggs src8 = (uint8_t *) INBUF_L(i).l_addr; 322 1.6 briggs *dst8 ^= *src8; 323 1.6 briggs } 324 1.6 briggs dst8++; 325 1.6 briggs } 326 1.6 briggs } 327 1.8 perry 328 1.6 briggs break; 329 1.6 briggs 330 1.6 briggs case DMOVER_BUF_UIO: 331 1.6 briggs { 332 1.6 briggs struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio; 333 1.6 briggs struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio; 334 1.6 briggs struct uio *uio; 335 1.14 christos char cp[1024], dst[1024]; 336 1.6 briggs size_t count, buflen; 337 1.6 briggs int error; 338 1.6 briggs 339 1.6 briggs if (uio_in->uio_rw != UIO_WRITE || 340 1.6 briggs uio_out->uio_rw != UIO_READ || 341 1.6 briggs uio_in->uio_resid != uio_out->uio_resid) { 342 1.6 briggs /* XXXLOCK */ 343 1.6 briggs dreq->dreq_error = EINVAL; 344 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR; 345 1.6 briggs /* XXXUNLOCK */ 346 1.6 briggs break; 347 1.6 briggs } 348 1.6 briggs 349 1.6 briggs buflen = uio_in->uio_resid; 350 1.14 christos if (buflen > sizeof(cp)) 351 1.14 christos buflen = sizeof(cp); 352 1.6 briggs 353 1.6 briggs /* 354 1.6 briggs * For each block, copy first input buffer into the destination 355 1.6 briggs * buffer and then read the rest, one by one, into a temporary 356 1.6 briggs * buffer and xor into the destination buffer. After all of 357 1.6 briggs * the inputs have been xor'd in, move the destination buffer 358 1.6 briggs * out and loop. 359 1.6 briggs */ 360 1.6 briggs while ((count = uio_in->uio_resid) != 0) { 361 1.6 briggs if (count > buflen) 362 1.6 briggs count = buflen; 363 1.6 briggs error = uiomove(dst, count, uio_in); 364 1.6 briggs if (error) { 365 1.6 briggs /* XXXLOCK */ 366 1.6 briggs dreq->dreq_error = error; 367 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR; 368 1.6 briggs /* XXXUNLOCK */ 369 1.6 briggs break; 370 1.6 briggs } 371 1.6 briggs for (i=1 ; (i < ninputs) && (error == 0) ; i++) { 372 1.6 briggs uio = dreq->dreq_inbuf[i].dmbuf_uio; 373 1.6 briggs error = uiomove(cp, count, uio); 374 1.6 briggs if (error == 0) { 375 1.6 briggs xor2(dst, dst, cp, count); 376 1.6 briggs } 377 1.6 briggs } 378 1.6 briggs if (error == 0) { 379 1.6 briggs error = uiomove(dst, count, uio_out); 380 1.6 briggs } else { 381 1.6 briggs /* XXXLOCK */ 382 1.6 briggs dreq->dreq_error = error; 383 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR; 384 1.6 briggs /* XXXUNLOCK */ 385 1.6 briggs break; 386 1.6 briggs } 387 1.6 briggs } 388 1.6 briggs break; 389 1.6 briggs } 390 1.6 briggs 391 1.6 briggs default: 392 1.6 briggs /* XXXLOCK */ 393 1.6 briggs dreq->dreq_error = EINVAL; 394 1.6 briggs dreq->dreq_flags |= DMOVER_REQ_ERROR; 395 1.6 briggs /* XXXUNLOCK */ 396 1.6 briggs } 397 1.6 briggs 398 1.6 briggs done: 399 1.6 briggs dmover_done(dreq); 400 1.6 briggs } 401 1.6 briggs 402 1.1 thorpej /* 403 1.1 thorpej * swdmover_func_copy_process: 404 1.1 thorpej * 405 1.1 thorpej * Processing routine for the "copy" function. 406 1.1 thorpej */ 407 1.1 thorpej static void 408 1.1 thorpej swdmover_func_copy_process(struct dmover_request *dreq) 409 1.1 thorpej { 410 1.1 thorpej 411 1.4 thorpej /* XXX Currently, both buffers must be of same type. */ 412 1.4 thorpej if (dreq->dreq_inbuf_type != dreq->dreq_outbuf_type) { 413 1.4 thorpej /* XXXLOCK */ 414 1.4 thorpej dreq->dreq_error = EINVAL; 415 1.4 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 416 1.4 thorpej /* XXXUNLOCK */ 417 1.4 thorpej goto done; 418 1.4 thorpej } 419 1.4 thorpej 420 1.1 thorpej switch (dreq->dreq_outbuf_type) { 421 1.1 thorpej case DMOVER_BUF_LINEAR: 422 1.1 thorpej if (dreq->dreq_outbuf.dmbuf_linear.l_len != 423 1.1 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_len) { 424 1.1 thorpej /* XXXLOCK */ 425 1.1 thorpej dreq->dreq_error = EINVAL; 426 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 427 1.1 thorpej /* XXXUNLOCK */ 428 1.1 thorpej break; 429 1.1 thorpej } 430 1.1 thorpej memcpy(dreq->dreq_outbuf.dmbuf_linear.l_addr, 431 1.1 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_addr, 432 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len); 433 1.1 thorpej break; 434 1.1 thorpej 435 1.1 thorpej case DMOVER_BUF_UIO: 436 1.1 thorpej { 437 1.1 thorpej struct uio *uio_out = dreq->dreq_outbuf.dmbuf_uio; 438 1.1 thorpej struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio; 439 1.14 christos char cp[1024]; 440 1.1 thorpej size_t count, buflen; 441 1.1 thorpej int error; 442 1.1 thorpej 443 1.1 thorpej if (uio_in->uio_rw != UIO_WRITE || 444 1.1 thorpej uio_out->uio_rw != UIO_READ || 445 1.1 thorpej uio_in->uio_resid != uio_out->uio_resid) { 446 1.1 thorpej /* XXXLOCK */ 447 1.1 thorpej dreq->dreq_error = EINVAL; 448 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 449 1.1 thorpej /* XXXUNLOCK */ 450 1.1 thorpej break; 451 1.1 thorpej } 452 1.1 thorpej 453 1.1 thorpej buflen = uio_in->uio_resid; 454 1.14 christos if (buflen > sizeof(cp)) 455 1.14 christos buflen = sizeof(cp); 456 1.1 thorpej 457 1.1 thorpej while ((count = uio_in->uio_resid) != 0) { 458 1.1 thorpej if (count > buflen) 459 1.1 thorpej count = buflen; 460 1.1 thorpej error = uiomove(cp, count, uio_in); 461 1.1 thorpej if (error == 0) 462 1.1 thorpej error = uiomove(cp, count, uio_out); 463 1.1 thorpej if (error) { 464 1.1 thorpej /* XXXLOCK */ 465 1.1 thorpej dreq->dreq_error = error; 466 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 467 1.1 thorpej /* XXXUNLOCK */ 468 1.1 thorpej break; 469 1.1 thorpej } 470 1.1 thorpej } 471 1.1 thorpej break; 472 1.1 thorpej } 473 1.3 thorpej 474 1.3 thorpej default: 475 1.3 thorpej /* XXXLOCK */ 476 1.3 thorpej dreq->dreq_error = EINVAL; 477 1.3 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 478 1.3 thorpej /* XXXUNLOCK */ 479 1.1 thorpej } 480 1.1 thorpej 481 1.4 thorpej done: 482 1.1 thorpej dmover_done(dreq); 483 1.1 thorpej } 484 1.1 thorpej 485 1.5 thorpej static const uint32_t iscsi_crc32c_table[256] = { 486 1.5 thorpej 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 487 1.5 thorpej 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, 488 1.5 thorpej 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 489 1.5 thorpej 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 490 1.5 thorpej 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 491 1.5 thorpej 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, 492 1.5 thorpej 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 493 1.5 thorpej 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, 494 1.5 thorpej 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 495 1.5 thorpej 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 496 1.5 thorpej 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 497 1.5 thorpej 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, 498 1.5 thorpej 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 499 1.5 thorpej 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, 500 1.5 thorpej 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 501 1.5 thorpej 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 502 1.5 thorpej 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 503 1.5 thorpej 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, 504 1.5 thorpej 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 505 1.5 thorpej 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, 506 1.5 thorpej 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 507 1.5 thorpej 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 508 1.5 thorpej 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 509 1.5 thorpej 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, 510 1.5 thorpej 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 511 1.5 thorpej 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, 512 1.5 thorpej 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 513 1.5 thorpej 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 514 1.5 thorpej 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 515 1.5 thorpej 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, 516 1.5 thorpej 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 517 1.5 thorpej 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, 518 1.5 thorpej 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 519 1.5 thorpej 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 520 1.5 thorpej 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 521 1.5 thorpej 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, 522 1.5 thorpej 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 523 1.5 thorpej 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, 524 1.5 thorpej 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 525 1.5 thorpej 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 526 1.5 thorpej 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 527 1.5 thorpej 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, 528 1.5 thorpej 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 529 1.5 thorpej 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, 530 1.5 thorpej 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 531 1.5 thorpej 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 532 1.5 thorpej 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 533 1.5 thorpej 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, 534 1.5 thorpej 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 535 1.5 thorpej 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, 536 1.5 thorpej 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 537 1.5 thorpej 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 538 1.5 thorpej 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 539 1.5 thorpej 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, 540 1.5 thorpej 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 541 1.5 thorpej 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, 542 1.5 thorpej 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 543 1.5 thorpej 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 544 1.5 thorpej 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 545 1.5 thorpej 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, 546 1.5 thorpej 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 547 1.5 thorpej 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, 548 1.5 thorpej 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 549 1.5 thorpej 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351, 550 1.5 thorpej }; 551 1.5 thorpej 552 1.5 thorpej static uint32_t 553 1.5 thorpej iscsi_crc32c(const uint8_t *buf, size_t len, uint32_t last) 554 1.5 thorpej { 555 1.5 thorpej uint32_t crc = 0xffffffffU ^ last; 556 1.5 thorpej 557 1.5 thorpej while (len--) 558 1.5 thorpej crc = iscsi_crc32c_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8); 559 1.5 thorpej 560 1.5 thorpej return (crc ^ 0xffffffffU); 561 1.5 thorpej } 562 1.5 thorpej 563 1.5 thorpej /* 564 1.5 thorpej * swdmover_func_iscsi_crc32c_process: 565 1.5 thorpej * 566 1.5 thorpej * Processing routine for the "iscsi-crc32c" function. 567 1.5 thorpej */ 568 1.5 thorpej static void 569 1.5 thorpej swdmover_func_iscsi_crc32c_process(struct dmover_request *dreq) 570 1.5 thorpej { 571 1.5 thorpej uint32_t result; 572 1.5 thorpej 573 1.5 thorpej /* No output buffer; we use the immediate only. */ 574 1.5 thorpej if (dreq->dreq_outbuf_type != DMOVER_BUF_NONE) { 575 1.5 thorpej /* XXXLOCK */ 576 1.5 thorpej dreq->dreq_error = EINVAL; 577 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 578 1.5 thorpej /* XXXUNLOCK */ 579 1.5 thorpej goto done; 580 1.5 thorpej } 581 1.5 thorpej 582 1.5 thorpej memcpy(&result, dreq->dreq_immediate, sizeof(result)); 583 1.5 thorpej 584 1.5 thorpej switch (dreq->dreq_inbuf_type) { 585 1.5 thorpej case DMOVER_BUF_LINEAR: 586 1.5 thorpej result = iscsi_crc32c(dreq->dreq_inbuf[0].dmbuf_linear.l_addr, 587 1.5 thorpej dreq->dreq_inbuf[0].dmbuf_linear.l_len, result); 588 1.5 thorpej break; 589 1.5 thorpej 590 1.5 thorpej case DMOVER_BUF_UIO: 591 1.5 thorpej { 592 1.5 thorpej struct uio *uio_in = dreq->dreq_inbuf[0].dmbuf_uio; 593 1.14 christos uint8_t cp[1024]; 594 1.5 thorpej size_t count, buflen; 595 1.5 thorpej int error; 596 1.5 thorpej 597 1.5 thorpej if (uio_in->uio_rw != UIO_WRITE) { 598 1.5 thorpej /* XXXLOCK */ 599 1.5 thorpej dreq->dreq_error = EINVAL; 600 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 601 1.5 thorpej /* XXXUNLOCK */ 602 1.5 thorpej goto done; 603 1.5 thorpej } 604 1.5 thorpej 605 1.5 thorpej buflen = uio_in->uio_resid; 606 1.14 christos if (buflen > sizeof(cp)) 607 1.14 christos buflen = sizeof(cp); 608 1.5 thorpej 609 1.5 thorpej while ((count = uio_in->uio_resid) != 0) { 610 1.5 thorpej if (count > buflen) 611 1.5 thorpej count = buflen; 612 1.5 thorpej error = uiomove(cp, count, uio_in); 613 1.5 thorpej if (error) { 614 1.5 thorpej /* XXXLOCK */ 615 1.5 thorpej dreq->dreq_error = error; 616 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 617 1.5 thorpej /* XXXUNLOCK */ 618 1.5 thorpej goto done; 619 1.5 thorpej } else 620 1.5 thorpej result = iscsi_crc32c(cp, count, result); 621 1.5 thorpej } 622 1.5 thorpej break; 623 1.5 thorpej } 624 1.5 thorpej 625 1.5 thorpej default: 626 1.5 thorpej /* XXXLOCK */ 627 1.5 thorpej dreq->dreq_error = EINVAL; 628 1.5 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 629 1.5 thorpej /* XXXUNLOCK */ 630 1.5 thorpej goto done; 631 1.5 thorpej } 632 1.5 thorpej 633 1.5 thorpej memcpy(dreq->dreq_immediate, &result, sizeof(result)); 634 1.5 thorpej done: 635 1.5 thorpej dmover_done(dreq); 636 1.5 thorpej } 637 1.5 thorpej 638 1.1 thorpej static struct swdmover_function swdmover_func_zero = { 639 1.1 thorpej swdmover_func_zero_process 640 1.1 thorpej }; 641 1.1 thorpej 642 1.1 thorpej static struct swdmover_function swdmover_func_fill8 = { 643 1.1 thorpej swdmover_func_fill8_process 644 1.1 thorpej }; 645 1.1 thorpej 646 1.5 thorpej static struct swdmover_function swdmover_func_copy = { 647 1.1 thorpej swdmover_func_copy_process 648 1.1 thorpej }; 649 1.1 thorpej 650 1.6 briggs static struct swdmover_function swdmover_func_xor = { 651 1.6 briggs swdmover_func_xor_process 652 1.6 briggs }; 653 1.6 briggs 654 1.5 thorpej static struct swdmover_function swdmover_func_iscsi_crc32c = { 655 1.5 thorpej swdmover_func_iscsi_crc32c_process 656 1.5 thorpej }; 657 1.5 thorpej 658 1.1 thorpej const struct dmover_algdesc swdmover_algdescs[] = { 659 1.6 briggs { 660 1.6 briggs DMOVER_FUNC_XOR2, 661 1.6 briggs &swdmover_func_xor, 662 1.6 briggs 2 663 1.6 briggs }, 664 1.6 briggs { 665 1.6 briggs DMOVER_FUNC_XOR3, 666 1.6 briggs &swdmover_func_xor, 667 1.6 briggs 3 668 1.6 briggs }, 669 1.6 briggs { 670 1.6 briggs DMOVER_FUNC_XOR4, 671 1.6 briggs &swdmover_func_xor, 672 1.6 briggs 4 673 1.6 briggs }, 674 1.6 briggs { 675 1.6 briggs DMOVER_FUNC_XOR5, 676 1.6 briggs &swdmover_func_xor, 677 1.6 briggs 5 678 1.6 briggs }, 679 1.6 briggs { 680 1.6 briggs DMOVER_FUNC_XOR6, 681 1.6 briggs &swdmover_func_xor, 682 1.6 briggs 6 683 1.6 briggs }, 684 1.6 briggs { 685 1.6 briggs DMOVER_FUNC_XOR7, 686 1.6 briggs &swdmover_func_xor, 687 1.6 briggs 7 688 1.6 briggs }, 689 1.6 briggs { 690 1.6 briggs DMOVER_FUNC_XOR8, 691 1.6 briggs &swdmover_func_xor, 692 1.6 briggs 8 693 1.6 briggs }, 694 1.1 thorpej { 695 1.1 thorpej DMOVER_FUNC_ZERO, 696 1.1 thorpej &swdmover_func_zero, 697 1.1 thorpej 0 698 1.1 thorpej }, 699 1.1 thorpej { 700 1.1 thorpej DMOVER_FUNC_FILL8, 701 1.1 thorpej &swdmover_func_fill8, 702 1.1 thorpej 0 703 1.1 thorpej }, 704 1.1 thorpej { 705 1.1 thorpej DMOVER_FUNC_COPY, 706 1.1 thorpej &swdmover_func_copy, 707 1.1 thorpej 1 708 1.5 thorpej }, 709 1.5 thorpej { 710 1.5 thorpej DMOVER_FUNC_ISCSI_CRC32C, 711 1.5 thorpej &swdmover_func_iscsi_crc32c, 712 1.5 thorpej 1, 713 1.1 thorpej }, 714 1.1 thorpej }; 715 1.1 thorpej #define SWDMOVER_ALGDESC_COUNT \ 716 1.1 thorpej (sizeof(swdmover_algdescs) / sizeof(swdmover_algdescs[0])) 717 1.1 thorpej 718 1.1 thorpej /* 719 1.1 thorpej * swdmoverattach: 720 1.1 thorpej * 721 1.1 thorpej * Pesudo-device attach routine. 722 1.1 thorpej */ 723 1.1 thorpej void 724 1.1 thorpej swdmoverattach(int count) 725 1.1 thorpej { 726 1.10 ad int error; 727 1.1 thorpej 728 1.1 thorpej swdmover_backend.dmb_name = "swdmover"; 729 1.1 thorpej swdmover_backend.dmb_speed = 1; /* XXX */ 730 1.1 thorpej swdmover_backend.dmb_cookie = NULL; 731 1.1 thorpej swdmover_backend.dmb_algdescs = swdmover_algdescs; 732 1.1 thorpej swdmover_backend.dmb_nalgdescs = SWDMOVER_ALGDESC_COUNT; 733 1.1 thorpej swdmover_backend.dmb_process = swdmover_process; 734 1.1 thorpej 735 1.10 ad error = kthread_create(PRI_NONE, 0, NULL, swdmover_thread, 736 1.11 he &swdmover_backend, &swdmover_lwp, "swdmover"); 737 1.10 ad if (error) 738 1.10 ad printf("WARNING: unable to create swdmover thread, " 739 1.10 ad "error = %d\n", error); 740 1.1 thorpej 741 1.1 thorpej /* XXX Should only register this when kthread creation succeeds. */ 742 1.1 thorpej dmover_backend_register(&swdmover_backend); 743 1.1 thorpej } 744