I am liking this diff quite a bit but it needs more testers. So if you
are using softraid crypto please try this diff.
On Fri, Jun 17, 2011 at 07:53:05PM +0100, Owain Ainsworth wrote:
> So here's the problem: ENOMEM on io in a hba driver is bad juju.
>
> In more detail:
>
> When preparing for each io softraid crypto does a
> sr_crypto_getcryptop(). This operation does a few things:
>
> - allocate a uio and iovec from a pool.
> - if this is a read then allocate a dma buffer with dma_alloc (up to
> MAXPHYS, i.e. 64k)
> - allocate a cryptop to be used with the crypto(9) framework.
> - initialise the above for use in the io.
>
> So if you are getting very low on memory, one of these operations
> (probably the dma alloc) will fail. when this happens softraid returns
> XS_DRIVER_STUFFUP to scsi land. This returns an EIO back to callers.
>
> Now it is fairly common to use softdep in these situations, synchronous
> filesystems are sloooow. softdep has certain assumptions about how
> things will work. if a queued dependancy fails that invalidates these
> assumptions. softraid panics in this case. I used to hit this repeatedly
> (several times a day) before I bought more memory.
>
> in general, most disk controllers prealloc everything they need (that
> isn't passed down to them) so that this won't be a problem.
>
> This diff does the same for softraid crypto. It'll eat just over 1meg of
> kva, but it is hardly the only driver to need to do that.
>
> The only slightly scary thing here is the cryptodesc list manipulations
> (the comments explain why they are necesary).
>
> I'm typing from a machine that runs this. todd@ is also testing it and
> marco kindly did some horrible io torture on a machine running this too
> and it runs quite nicely.
>
> A side benefit is that due to missing out allocations in every disk io
> this is actually slightly faster in io too.
>
> More testing would be appreciated. Cheers,
>
> -0-
>
> diff --git dev/softraid_crypto.c dev/softraid_crypto.c
> index 3259121..a60824e 100644
> --- dev/softraid_crypto.c
> +++ dev/softraid_crypto.c
> @@ -56,9 +56,26 @@
> #include <dev/softraidvar.h>
> #include <dev/rndvar.h>
>
> -struct cryptop *sr_crypto_getcryptop(struct sr_workunit *, int);
> +/*
> + * the per-io data that we need to preallocate. We can't afford to allow io
> + * to start failing when memory pressure kicks in.
> + * We can store this in the WU because we assert that only one
> + * ccb per WU will ever be active.
> + */
> +struct sr_crypto_wu {
> + TAILQ_ENTRY(sr_crypto_wu) cr_link;
> + struct uio cr_uio;
> + struct iovec cr_iov;
> + struct cryptop *cr_crp;
> + struct cryptodesc *cr_descs;
> + struct sr_workunit *cr_wu;
> + void *cr_dmabuf;
> +};
> +
> +
> +struct sr_crypto_wu *sr_crypto_wu_get(struct sr_workunit *, int);
> +void sr_crypto_wu_put(struct sr_crypto_wu *);
> int sr_crypto_create_keys(struct sr_discipline *);
> -void *sr_crypto_putcryptop(struct cryptop *);
> int sr_crypto_get_kdf(struct bioc_createraid *,
> struct sr_discipline *);
> int sr_crypto_decrypt(u_char *, u_char *, u_char *, size_t, int);
> @@ -78,7 +95,7 @@ int sr_crypto_meta_opt_load(struct sr_discipline *,
> struct sr_meta_opt *);
> int sr_crypto_write(struct cryptop *);
> int sr_crypto_rw(struct sr_workunit *);
> -int sr_crypto_rw2(struct sr_workunit *, struct cryptop *);
> +int sr_crypto_rw2(struct sr_workunit *, struct sr_crypto_wu *);
> void sr_crypto_intr(struct buf *);
> int sr_crypto_read(struct cryptop *);
> void sr_crypto_finish_io(struct sr_workunit *);
> @@ -230,40 +247,35 @@ done:
> return (rv);
> }
>
> -struct cryptop *
> -sr_crypto_getcryptop(struct sr_workunit *wu, int encrypt)
> +
> +struct sr_crypto_wu *
> +sr_crypto_wu_get(struct sr_workunit *wu, int encrypt)
> {
> struct scsi_xfer *xs = wu->swu_xs;
> struct sr_discipline *sd = wu->swu_dis;
> - struct cryptop *crp = NULL;
> + struct sr_crypto_wu *crwu;
> struct cryptodesc *crd;
> - struct uio *uio = NULL;
> - int flags, i, n, s;
> + int flags, i, n;
> daddr64_t blk = 0;
> u_int keyndx;
>
> - DNPRINTF(SR_D_DIS, "%s: sr_crypto_getcryptop wu: %p encrypt: %d\n",
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_wu_get wu: %p encrypt: %d\n",
> DEVNAME(sd->sd_sc), wu, encrypt);
>
> - s = splbio();
> - uio = pool_get(&sd->mds.mdd_crypto.sr_uiopl, PR_ZERO | PR_NOWAIT);
> - if (uio == NULL)
> - goto poolunwind;
> - uio->uio_iov = pool_get(&sd->mds.mdd_crypto.sr_iovpl,
> - PR_ZERO | PR_NOWAIT);
> - if (uio->uio_iov == NULL)
> - goto poolunwind;
> - splx(s);
> + mtx_enter(&sd->mds.mdd_crypto.scr_mutex);
> + if ((crwu = TAILQ_FIRST(&sd->mds.mdd_crypto.scr_wus)) != NULL)
> + TAILQ_REMOVE(&sd->mds.mdd_crypto.scr_wus, crwu, cr_link);
> + mtx_leave(&sd->mds.mdd_crypto.scr_mutex);
> + if (crwu == NULL)
> + panic("sr_crypto_wu_get: out of wus");
>
> - uio->uio_iovcnt = 1;
> - uio->uio_iov->iov_len = xs->datalen;
> + crwu->cr_uio.uio_iovcnt = 1;
> + crwu->cr_uio.uio_iov->iov_len = xs->datalen;
> if (xs->flags & SCSI_DATA_OUT) {
> - uio->uio_iov->iov_base = dma_alloc(xs->datalen, PR_NOWAIT);
> - if (uio->uio_iov->iov_base == NULL)
> - goto unwind;
> - bcopy(xs->data, uio->uio_iov->iov_base, xs->datalen);
> + crwu->cr_uio.uio_iov->iov_base = crwu->cr_dmabuf;
> + bcopy(xs->data, crwu->cr_uio.uio_iov->iov_base, xs->datalen);
> } else
> - uio->uio_iov->iov_base = xs->data;
> + crwu->cr_uio.uio_iov->iov_base = xs->data;
>
> if (xs->cmdlen == 10)
> blk = _4btol(((struct scsi_rw_big *)xs->cmd)->addr);
> @@ -273,25 +285,40 @@ sr_crypto_getcryptop(struct sr_workunit *wu, int
> encrypt)
> blk = _3btol(((struct scsi_rw *)xs->cmd)->addr);
>
> n = xs->datalen >> DEV_BSHIFT;
> +
> + /*
> + * we preallocated enough crypto descs for up to MAXPHYS of io.
> + * since ios may be less than that we need to tweak the linked list
> + * of crypto desc structures to be just long enough for our needs.
> + * Otherwise crypto will get upset with us. So put n descs on the crp
> + * and keep the rest.
> + */
> + crd = crwu->cr_descs;
> + i = 0;
> + while (++i < n) {
> + crd = crd->crd_next;
> + KASSERT(crd);
> + }
> + crwu->cr_crp->crp_desc = crwu->cr_descs;
> + crwu->cr_descs = crd->crd_next;
> + crd->crd_next = NULL;
> +
> flags = (encrypt ? CRD_F_ENCRYPT : 0) |
> CRD_F_IV_PRESENT | CRD_F_IV_EXPLICIT;
>
> - crp = crypto_getreq(n);
> - if (crp == NULL)
> - goto unwind;
> -
> /* Select crypto session based on block number */
> keyndx = blk >> SR_CRYPTO_KEY_BLKSHIFT;
> if (keyndx >= SR_CRYPTO_MAXKEYS)
> goto unwind;
> - crp->crp_sid = sd->mds.mdd_crypto.scr_sid[keyndx];
> - if (crp->crp_sid == (u_int64_t)-1)
> + crwu->cr_crp->crp_sid = sd->mds.mdd_crypto.scr_sid[keyndx];
> + if (crwu->cr_crp->crp_sid == (u_int64_t)-1)
> goto unwind;
>
> - crp->crp_ilen = xs->datalen;
> - crp->crp_alloctype = M_DEVBUF;
> - crp->crp_buf = uio;
> - for (i = 0, crd = crp->crp_desc; crd; i++, blk++, crd = crd->crd_next) {
> + crwu->cr_crp->crp_ilen = xs->datalen;
> + crwu->cr_crp->crp_alloctype = M_DEVBUF;
> + crwu->cr_crp->crp_buf = &crwu->cr_uio;
> + for (i = 0, crd = crwu->cr_crp->crp_desc; crd;
> + i++, blk++, crd = crd->crd_next) {
> crd->crd_skip = i << DEV_BSHIFT;
> crd->crd_len = DEV_BSIZE;
> crd->crd_inject = 0;
> @@ -311,48 +338,50 @@ sr_crypto_getcryptop(struct sr_workunit *wu, int
> encrypt)
> crd->crd_key = sd->mds.mdd_crypto.scr_key[0];
> bcopy(&blk, crd->crd_iv, sizeof(blk));
> }
> + crwu->cr_wu = wu;
> + crwu->cr_crp->crp_opaque = crwu;
>
> - return (crp);
> -poolunwind:
> - splx(s);
> + return (crwu);
> unwind:
> - if (crp)
> - crypto_freereq(crp);
> - if (uio && uio->uio_iov)
> - if ((wu->swu_xs->flags & SCSI_DATA_OUT) &&
> - uio->uio_iov->iov_base)
> - dma_free(uio->uio_iov->iov_base, uio->uio_iov->iov_len);
> -
> - s = splbio();
> - if (uio && uio->uio_iov)
> - pool_put(&sd->mds.mdd_crypto.sr_iovpl, uio->uio_iov);
> - if (uio)
> - pool_put(&sd->mds.mdd_crypto.sr_uiopl, uio);
> - splx(s);
> + /* steal the descrptions back from the cryptop */
> + crd = crwu->cr_crp->crp_desc;
> + while (crd->crd_next != NULL) {
> + crd = crd->crd_next;
> + }
>
> + /* join the lists back again */
> + crd->crd_next = crwu->cr_descs;
> + crwu->cr_descs = crwu->cr_crp->crp_desc;
> + crwu->cr_crp->crp_desc = NULL;
> return (NULL);
> }
>
> -void *
> -sr_crypto_putcryptop(struct cryptop *crp)
> +void
> +sr_crypto_wu_put(struct sr_crypto_wu *crwu)
> {
> - struct uio *uio = crp->crp_buf;
> - struct sr_workunit *wu = crp->crp_opaque;
> + struct cryptop *crp = crwu->cr_crp;
> + struct sr_workunit *wu = crwu->cr_wu;
> struct sr_discipline *sd = wu->swu_dis;
> - int s;
> + struct cryptodesc *crd;
>
> - DNPRINTF(SR_D_DIS, "%s: sr_crypto_putcryptop crp: %p\n",
> - DEVNAME(wu->swu_dis->sd_sc), crp);
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_wu_put crwu: %p\n",
> + DEVNAME(wu->swu_dis->sd_sc), crwu);
>
> - if ((wu->swu_xs->flags & SCSI_DATA_OUT) && uio->uio_iov->iov_base)
> - dma_free(uio->uio_iov->iov_base, uio->uio_iov->iov_len);
> - s = splbio();
> - pool_put(&sd->mds.mdd_crypto.sr_iovpl, uio->uio_iov);
> - pool_put(&sd->mds.mdd_crypto.sr_uiopl, uio);
> - splx(s);
> - crypto_freereq(crp);
> + /* steal the descrptions back from the cryptop */
> + crd = crp->crp_desc;
> + KASSERT(crd);
> + while (crd->crd_next != NULL) {
> + crd = crd->crd_next;
> + }
> +
> + /* join the lists back again */
> + crd->crd_next = crwu->cr_descs;
> + crwu->cr_descs = crp->crp_desc;
> + crp->crp_desc = NULL;
>
> - return (wu);
> + mtx_enter(&sd->mds.mdd_crypto.scr_mutex);
> + TAILQ_INSERT_TAIL(&sd->mds.mdd_crypto.scr_wus, crwu, cr_link);
> + mtx_leave(&sd->mds.mdd_crypto.scr_mutex);
> }
>
> int
> @@ -928,6 +957,7 @@ int
> sr_crypto_alloc_resources(struct sr_discipline *sd)
> {
> struct cryptoini cri;
> + struct sr_crypto_wu *crwu;
> u_int num_keys, i;
>
> if (!sd)
> @@ -936,11 +966,6 @@ sr_crypto_alloc_resources(struct sr_discipline *sd)
> DNPRINTF(SR_D_DIS, "%s: sr_crypto_alloc_resources\n",
> DEVNAME(sd->sd_sc));
>
> - pool_init(&sd->mds.mdd_crypto.sr_uiopl, sizeof(struct uio), 0, 0, 0,
> - "sr_uiopl", NULL);
> - pool_init(&sd->mds.mdd_crypto.sr_iovpl, sizeof(struct iovec), 0, 0, 0,
> - "sr_iovpl", NULL);
> -
> for (i = 0; i < SR_CRYPTO_MAXKEYS; i++)
> sd->mds.mdd_crypto.scr_sid[i] = (u_int64_t)-1;
>
> @@ -950,6 +975,33 @@ sr_crypto_alloc_resources(struct sr_discipline *sd)
> return (ENOMEM);
> if (sr_crypto_decrypt_key(sd))
> return (EPERM);
> + /*
> + * For each wu allocate the uio, iovec and crypto structures.
> + * these have to be allocated now because during runtime we can't
> + * fail an allocation without failing the io (which can cause real
> + * problems).
> + */
> + mtx_init(&sd->mds.mdd_crypto.scr_mutex, IPL_BIO);
> + TAILQ_INIT(&sd->mds.mdd_crypto.scr_wus);
> + for (i = 0; i < sd->sd_max_wu; i++) {
> + crwu = malloc(sizeof(*crwu), M_DEVBUF,
> + M_WAITOK | M_ZERO | M_CANFAIL);
> + if (crwu == NULL)
> + return (ENOMEM);
> + /* put it on the list now so if we fail it'll be freed */
> + mtx_enter(&sd->mds.mdd_crypto.scr_mutex);
> + TAILQ_INSERT_TAIL(&sd->mds.mdd_crypto.scr_wus, crwu, cr_link);
> + mtx_leave(&sd->mds.mdd_crypto.scr_mutex);
> +
> + crwu->cr_uio.uio_iov = &crwu->cr_iov;
> + crwu->cr_dmabuf = dma_alloc(MAXPHYS, PR_WAITOK);
> + crwu->cr_crp = crypto_getreq(MAXPHYS >> DEV_BSHIFT);
> + if (crwu->cr_crp == NULL)
> + return (ENOMEM);
> + /* steal the list of cryptodescs */
> + crwu->cr_descs = crwu->cr_crp->crp_desc;
> + crwu->cr_crp->crp_desc = NULL;
> + }
>
> bzero(&cri, sizeof(cri));
> cri.cri_alg = CRYPTO_AES_XTS;
> @@ -992,6 +1044,7 @@ int
> sr_crypto_free_resources(struct sr_discipline *sd)
> {
> int rv = EINVAL;
> + struct sr_crypto_wu *crwu;
> u_int i;
>
> if (!sd)
> @@ -1013,14 +1066,21 @@ sr_crypto_free_resources(struct sr_discipline *sd)
> sd->mds.mdd_crypto.scr_sid[i] = (u_int64_t)-1;
> }
>
> + while ((crwu = TAILQ_FIRST(&sd->mds.mdd_crypto.scr_wus)) != NULL) {
> + TAILQ_REMOVE(&sd->mds.mdd_crypto.scr_wus, crwu, cr_link);
> +
> + dma_free(crwu->cr_dmabuf, MAXPHYS);
> + /* twiddle cryptoreq back */
> + if (crwu->cr_crp) {
> + crwu->cr_crp->crp_desc = crwu->cr_descs;
> + crypto_freereq(crwu->cr_crp);
> + }
> + free(crwu, M_DEVBUF);
> + }
> +
> sr_wu_free(sd);
> sr_ccb_free(sd);
>
> - if (sd->mds.mdd_crypto.sr_uiopl.pr_serial != 0)
> - pool_destroy(&sd->mds.mdd_crypto.sr_uiopl);
> - if (sd->mds.mdd_crypto.sr_iovpl.pr_serial != 0)
> - pool_destroy(&sd->mds.mdd_crypto.sr_iovpl);
> -
> rv = 0;
> return (rv);
> }
> @@ -1104,23 +1164,22 @@ sr_crypto_meta_opt_load(struct sr_discipline *sd,
> struct sr_meta_opt *om)
> int
> sr_crypto_rw(struct sr_workunit *wu)
> {
> - struct cryptop *crp;
> + struct sr_crypto_wu *crwu;
> int s, rv = 0;
>
> DNPRINTF(SR_D_DIS, "%s: sr_crypto_rw wu: %p\n",
> DEVNAME(wu->swu_dis->sd_sc), wu);
>
> if (wu->swu_xs->flags & SCSI_DATA_OUT) {
> - crp = sr_crypto_getcryptop(wu, 1);
> - if (crp == NULL)
> + crwu = sr_crypto_wu_get(wu, 1);
> + if (crwu == NULL)
> return (1);
> - crp->crp_callback = sr_crypto_write;
> - crp->crp_opaque = wu;
> + crwu->cr_crp->crp_callback = sr_crypto_write;
> s = splvm();
> - if (crypto_invoke(crp))
> + if (crypto_invoke(crwu->cr_crp))
> rv = 1;
> else
> - rv = crp->crp_etype;
> + rv = crwu->cr_crp->crp_etype;
> splx(s);
> } else
> rv = sr_crypto_rw2(wu, NULL);
> @@ -1131,26 +1190,26 @@ sr_crypto_rw(struct sr_workunit *wu)
> int
> sr_crypto_write(struct cryptop *crp)
> {
> + struct sr_crypto_wu *crwu = crp->crp_opaque;
> + struct sr_workunit *wu = crwu->cr_wu;
> int s;
> - struct sr_workunit *wu = crp->crp_opaque;
>
> DNPRINTF(SR_D_INTR, "%s: sr_crypto_write: wu %x xs: %x\n",
> DEVNAME(wu->swu_dis->sd_sc), wu, wu->swu_xs);
>
> if (crp->crp_etype) {
> /* fail io */
> - ((struct sr_workunit *)(crp->crp_opaque))->swu_xs->error =
> - XS_DRIVER_STUFFUP;
> + wu->swu_xs->error = XS_DRIVER_STUFFUP;
> s = splbio();
> - sr_crypto_finish_io(crp->crp_opaque);
> + sr_crypto_finish_io(wu);
> splx(s);
> }
>
> - return (sr_crypto_rw2(wu, crp));
> + return (sr_crypto_rw2(wu, crwu));
> }
>
> int
> -sr_crypto_rw2(struct sr_workunit *wu, struct cryptop *crp)
> +sr_crypto_rw2(struct sr_workunit *wu, struct sr_crypto_wu *crwu)
> {
> struct sr_discipline *sd = wu->swu_dis;
> struct scsi_xfer *xs = wu->swu_xs;
> @@ -1185,10 +1244,10 @@ sr_crypto_rw2(struct sr_workunit *wu, struct cryptop
> *crp)
> ccb->ccb_buf.b_flags |= B_READ;
> ccb->ccb_buf.b_data = xs->data;
> } else {
> - uio = crp->crp_buf;
> + uio = crwu->cr_crp->crp_buf;
> ccb->ccb_buf.b_flags |= B_WRITE;
> ccb->ccb_buf.b_data = uio->uio_iov->iov_base;
> - ccb->ccb_opaque = crp;
> + ccb->ccb_opaque = crwu;
> }
>
> ccb->ccb_buf.b_error = 0;
> @@ -1224,8 +1283,8 @@ queued:
> return (0);
> bad:
> /* wu is unwound by sr_wu_put */
> - if (crp)
> - crp->crp_etype = EINVAL;
> + if (crwu)
> + crwu->cr_crp->crp_etype = EINVAL;
> return (1);
> }
>
> @@ -1237,7 +1296,7 @@ sr_crypto_intr(struct buf *bp)
> struct sr_discipline *sd = wu->swu_dis;
> struct scsi_xfer *xs = wu->swu_xs;
> struct sr_softc *sc = sd->sd_sc;
> - struct cryptop *crp;
> + struct sr_crypto_wu *crwu;
> int s, s2, pend;
>
> DNPRINTF(SR_D_INTR, "%s: sr_crypto_intr bp: %x xs: %x\n",
> @@ -1296,16 +1355,16 @@ sr_crypto_intr(struct buf *bp)
> DEVNAME(sc), wu);
>
> if ((xs->flags & SCSI_DATA_IN) && (xs->error == XS_NOERROR)) {
> - crp = sr_crypto_getcryptop(wu, 0);
> - if (crp == NULL)
> - panic("sr_crypto_intr: no crypto op");
> - ccb->ccb_opaque = crp;
> - crp->crp_callback = sr_crypto_read;
> - crp->crp_opaque = wu;
> + /* only fails on implementation error */
> + crwu = sr_crypto_wu_get(wu, 0);
> + if (crwu == NULL)
> + panic("sr_crypto_intr: no wu");
> + crwu->cr_crp->crp_callback = sr_crypto_read;
> + ccb->ccb_opaque = crwu;
> DNPRINTF(SR_D_INTR, "%s: sr_crypto_intr: crypto_invoke "
> - "%p\n", DEVNAME(sc), crp);
> + "%p\n", DEVNAME(sc), crwu->cr_crp);
> s2 = splvm();
> - crypto_invoke(crp);
> + crypto_invoke(crwu->cr_crp);
> splx(s2);
> goto done;
> }
> @@ -1339,7 +1398,7 @@ sr_crypto_finish_io(struct sr_workunit *wu)
> TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link) {
> if (ccb->ccb_opaque == NULL)
> continue;
> - sr_crypto_putcryptop(ccb->ccb_opaque);
> + sr_crypto_wu_put(ccb->ccb_opaque);
> }
>
> sr_scsi_done(sd, xs);
> @@ -1351,8 +1410,9 @@ sr_crypto_finish_io(struct sr_workunit *wu)
> int
> sr_crypto_read(struct cryptop *crp)
> {
> + struct sr_crypto_wu *crwu = crp->crp_opaque;
> + struct sr_workunit *wu = crwu->cr_wu;
> int s;
> - struct sr_workunit *wu = crp->crp_opaque;
>
> DNPRINTF(SR_D_INTR, "%s: sr_crypto_read: wu %x xs: %x\n",
> DEVNAME(wu->swu_dis->sd_sc), wu, wu->swu_xs);
> diff --git dev/softraid_vnode.c dev/softraid_vnode.c
> new file mode 100644
> index 0000000..2c362d5
> --- /dev/null
> +++ dev/softraid_vnode.c
> @@ -0,0 +1,1378 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2011 Owain G. Ainsworth <[email protected]>
> + * Copyright (c) 2008 Hans-Joerg Hoexer <[email protected]>
> + * Copyright (c) 2008 Damien Miller <[email protected]>
> + * Copyright (c) 2009 Joel Sing <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include "bio.h"
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/buf.h>
> +#include <sys/device.h>
> +#include <sys/ioctl.h>
> +#include <sys/proc.h>
> +#include <sys/malloc.h>
> +#include <sys/pool.h>
> +#include <sys/kernel.h>
> +#include <sys/disk.h>
> +#include <sys/rwlock.h>
> +#include <sys/queue.h>
> +#include <sys/fcntl.h>
> +#include <sys/disklabel.h>
> +#include <sys/mount.h>
> +#include <sys/sensors.h>
> +#include <sys/stat.h>
> +#include <sys/conf.h>
> +#include <sys/uio.h>
> +#include <sys/dkio.h>
> +
> +#include <crypto/cryptodev.h>
> +#include <crypto/cryptosoft.h>
> +#include <crypto/rijndael.h>
> +#include <crypto/md5.h>
> +#include <crypto/sha1.h>
> +#include <crypto/sha2.h>
> +#include <crypto/hmac.h>
> +
> +#include <scsi/scsi_all.h>
> +#include <scsi/scsiconf.h>
> +#include <scsi/scsi_disk.h>
> +
> +#include <dev/softraidvar.h>
> +#include <dev/rndvar.h>
> +
> +struct cryptop *sr_crypto_getcryptop(struct sr_workunit *, int);
> +int sr_crypto_create_keys(struct sr_discipline *);
> +void *sr_crypto_putcryptop(struct cryptop *);
> +int sr_crypto_get_kdf(struct bioc_createraid *,
> + struct sr_discipline *);
> +int sr_crypto_decrypt(u_char *, u_char *, u_char *, size_t, int);
> +int sr_crypto_encrypt(u_char *, u_char *, u_char *, size_t, int);
> +int sr_crypto_decrypt_key(struct sr_discipline *);
> +int sr_crypto_change_maskkey(struct sr_discipline *,
> + struct sr_crypto_kdfinfo *, struct sr_crypto_kdfinfo *);
> +int sr_crypto_create(struct sr_discipline *,
> + struct bioc_createraid *, int, int64_t);
> +int sr_crypto_assemble(struct sr_discipline *,
> + struct bioc_createraid *, int);
> +int sr_crypto_alloc_resources(struct sr_discipline *);
> +int sr_crypto_free_resources(struct sr_discipline *);
> +int sr_crypto_ioctl(struct sr_discipline *,
> + struct bioc_discipline *);
> +int sr_crypto_meta_opt_load(struct sr_discipline *,
> + struct sr_meta_opt *);
> +int sr_crypto_write(struct cryptop *);
> +int sr_crypto_rw(struct sr_workunit *);
> +int sr_crypto_rw2(struct sr_workunit *, struct cryptop *);
> +void sr_crypto_intr(struct buf *);
> +int sr_crypto_read(struct cryptop *);
> +void sr_crypto_finish_io(struct sr_workunit *);
> +void sr_crypto_calculate_check_hmac_sha1(u_int8_t *, int,
> + u_int8_t *, int, u_char *);
> +void sr_crypto_hotplug(struct sr_discipline *, struct disk *, int);
> +
> +#ifdef SR_DEBUG0
> +void sr_crypto_dumpkeys(struct sr_discipline *);
> +#endif
> +
> +/* Discipline initialisation. */
> +void
> +sr_crypto_discipline_init(struct sr_discipline *sd)
> +{
> + int i;
> +
> + /* Fill out discipline members. */
> + sd->sd_type = SR_MD_CRYPTO;
> + sd->sd_capabilities = SR_CAP_SYSTEM_DISK;
> + sd->sd_max_wu = SR_CRYPTO_NOWU;
> +
> + for (i = 0; i < SR_CRYPTO_MAXKEYS; i++)
> + sd->mds.mdd_crypto.scr_sid[i] = (u_int64_t)-1;
> +
> + /* Setup discipline pointers. */
> + sd->sd_create = sr_crypto_create;
> + sd->sd_assemble = sr_crypto_assemble;
> + sd->sd_alloc_resources = sr_crypto_alloc_resources;
> + sd->sd_free_resources = sr_crypto_free_resources;
> + sd->sd_start_discipline = NULL;
> + sd->sd_ioctl_handler = sr_crypto_ioctl;
> + sd->sd_meta_opt_load = sr_crypto_meta_opt_load;
> + sd->sd_scsi_inquiry = sr_raid_inquiry;
> + sd->sd_scsi_read_cap = sr_raid_read_cap;
> + sd->sd_scsi_tur = sr_raid_tur;
> + sd->sd_scsi_req_sense = sr_raid_request_sense;
> + sd->sd_scsi_start_stop = sr_raid_start_stop;
> + sd->sd_scsi_sync = sr_raid_sync;
> + sd->sd_scsi_rw = sr_crypto_rw;
> + /* XXX reuse raid 1 functions for now FIXME */
> + sd->sd_set_chunk_state = sr_raid1_set_chunk_state;
> + sd->sd_set_vol_state = sr_raid1_set_vol_state;
> +}
> +
> +int
> +sr_crypto_create(struct sr_discipline *sd, struct bioc_createraid *bc,
> + int no_chunk, int64_t coerced_size)
> +{
> + struct sr_meta_opt_item *omi;
> + int rv = EINVAL;
> +
> + if (no_chunk != 1)
> + goto done;
> +
> + /* Create crypto optional metadata. */
> + omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF,
> + M_WAITOK | M_ZERO);
> + omi->omi_om.somi.som_type = SR_OPT_CRYPTO;
> + SLIST_INSERT_HEAD(&sd->sd_meta_opt, omi, omi_link);
> + sd->mds.mdd_crypto.scr_meta = &omi->omi_om.somi.som_meta.smm_crypto;
> + sd->sd_meta->ssdi.ssd_opt_no++;
> +
> + sd->mds.mdd_crypto.key_disk = NULL;
> +
> + if (bc->bc_key_disk != NODEV) {
> +
> + /* Create a key disk. */
> + if (sr_crypto_get_kdf(bc, sd))
> + goto done;
> + sd->mds.mdd_crypto.key_disk =
> + sr_crypto_create_key_disk(sd, bc->bc_key_disk);
> + if (sd->mds.mdd_crypto.key_disk == NULL)
> + goto done;
> + sd->sd_capabilities |= SR_CAP_AUTO_ASSEMBLE;
> +
> + } else if (bc->bc_opaque_flags & BIOC_SOOUT) {
> +
> + /* No hint available yet. */
> + bc->bc_opaque_status = BIOC_SOINOUT_FAILED;
> + rv = EAGAIN;
> + goto done;
> +
> + } else if (sr_crypto_get_kdf(bc, sd))
> + goto done;
> +
> + /* Passphrase volumes cannot be automatically assembled. */
> + if (!(bc->bc_flags & BIOC_SCNOAUTOASSEMBLE) && bc->bc_key_disk == NODEV)
> + goto done;
> +
> + strlcpy(sd->sd_name, "CRYPTO", sizeof(sd->sd_name));
> + sd->sd_meta->ssdi.ssd_size = coerced_size;
> +
> + sr_crypto_create_keys(sd);
> +
> + sd->sd_max_ccb_per_wu = no_chunk;
> +
> + rv = 0;
> +done:
> + return (rv);
> +}
> +
> +int
> +sr_crypto_assemble(struct sr_discipline *sd, struct bioc_createraid *bc,
> + int no_chunk)
> +{
> + int rv = EINVAL;
> +
> + sd->mds.mdd_crypto.key_disk = NULL;
> +
> + /* Crypto optional metadata must already exist... */
> + if (sd->mds.mdd_crypto.scr_meta == NULL)
> + goto done;
> +
> + if (bc->bc_key_disk != NODEV) {
> + /* Read the mask key from the key disk. */
> + sd->mds.mdd_crypto.key_disk =
> + sr_crypto_read_key_disk(sd, bc->bc_key_disk);
> + if (sd->mds.mdd_crypto.key_disk == NULL)
> + goto done;
> + } else if (bc->bc_opaque_flags & BIOC_SOOUT) {
> + /* provide userland with kdf hint */
> + if (bc->bc_opaque == NULL)
> + goto done;
> +
> + if (sizeof(sd->mds.mdd_crypto.scr_meta->scm_kdfhint) <
> + bc->bc_opaque_size)
> + goto done;
> +
> + if (copyout(sd->mds.mdd_crypto.scr_meta->scm_kdfhint,
> + bc->bc_opaque, bc->bc_opaque_size))
> + goto done;
> +
> + /* we're done */
> + bc->bc_opaque_status = BIOC_SOINOUT_OK;
> + rv = EAGAIN;
> + goto done;
> + } else if (bc->bc_opaque_flags & BIOC_SOIN) {
> + /* get kdf with maskkey from userland */
> + if (sr_crypto_get_kdf(bc, sd))
> + goto done;
> +
> + }
> +
> + sd->sd_max_ccb_per_wu = sd->sd_meta->ssdi.ssd_chunk_no;
> +
> + rv = 0;
> +done:
> + return (rv);
> +}
> +
> +struct cryptop *
> +sr_crypto_getcryptop(struct sr_workunit *wu, int encrypt)
> +{
> + struct scsi_xfer *xs = wu->swu_xs;
> + struct sr_discipline *sd = wu->swu_dis;
> + struct cryptop *crp = NULL;
> + struct cryptodesc *crd;
> + struct uio *uio = NULL;
> + int flags, i, n, s;
> + daddr64_t blk = 0;
> + u_int keyndx;
> +
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_getcryptop wu: %p encrypt: %d\n",
> + DEVNAME(sd->sd_sc), wu, encrypt);
> +
> + s = splbio();
> + uio = pool_get(&sd->mds.mdd_crypto.sr_uiopl, PR_ZERO | PR_NOWAIT);
> + if (uio == NULL)
> + goto poolunwind;
> + uio->uio_iov = pool_get(&sd->mds.mdd_crypto.sr_iovpl,
> + PR_ZERO | PR_NOWAIT);
> + if (uio->uio_iov == NULL)
> + goto poolunwind;
> + splx(s);
> +
> + uio->uio_iovcnt = 1;
> + uio->uio_iov->iov_len = xs->datalen;
> + if (xs->flags & SCSI_DATA_OUT) {
> + uio->uio_iov->iov_base = dma_alloc(xs->datalen, PR_NOWAIT);
> + if (uio->uio_iov->iov_base == NULL)
> + goto unwind;
> + bcopy(xs->data, uio->uio_iov->iov_base, xs->datalen);
> + } else
> + uio->uio_iov->iov_base = xs->data;
> +
> + if (xs->cmdlen == 10)
> + blk = _4btol(((struct scsi_rw_big *)xs->cmd)->addr);
> + else if (xs->cmdlen == 16)
> + blk = _8btol(((struct scsi_rw_16 *)xs->cmd)->addr);
> + else if (xs->cmdlen == 6)
> + blk = _3btol(((struct scsi_rw *)xs->cmd)->addr);
> +
> + n = xs->datalen >> DEV_BSHIFT;
> + flags = (encrypt ? CRD_F_ENCRYPT : 0) |
> + CRD_F_IV_PRESENT | CRD_F_IV_EXPLICIT;
> +
> + crp = crypto_getreq(n);
> + if (crp == NULL)
> + goto unwind;
> +
> + /* Select crypto session based on block number */
> + keyndx = blk >> SR_CRYPTO_KEY_BLKSHIFT;
> + if (keyndx >= SR_CRYPTO_MAXKEYS)
> + goto unwind;
> + crp->crp_sid = sd->mds.mdd_crypto.scr_sid[keyndx];
> + if (crp->crp_sid == (u_int64_t)-1)
> + goto unwind;
> +
> + crp->crp_ilen = xs->datalen;
> + crp->crp_alloctype = M_DEVBUF;
> + crp->crp_buf = uio;
> + for (i = 0, crd = crp->crp_desc; crd; i++, blk++, crd = crd->crd_next) {
> + crd->crd_skip = i << DEV_BSHIFT;
> + crd->crd_len = DEV_BSIZE;
> + crd->crd_inject = 0;
> + crd->crd_flags = flags;
> + crd->crd_alg = CRYPTO_AES_XTS;
> +
> + switch (sd->mds.mdd_crypto.scr_meta->scm_alg) {
> + case SR_CRYPTOA_AES_XTS_128:
> + crd->crd_klen = 256;
> + break;
> + case SR_CRYPTOA_AES_XTS_256:
> + crd->crd_klen = 512;
> + break;
> + default:
> + goto unwind;
> + }
> + crd->crd_key = sd->mds.mdd_crypto.scr_key[0];
> + bcopy(&blk, crd->crd_iv, sizeof(blk));
> + }
> +
> + return (crp);
> +poolunwind:
> + splx(s);
> +unwind:
> + if (crp)
> + crypto_freereq(crp);
> + if (uio && uio->uio_iov)
> + if ((wu->swu_xs->flags & SCSI_DATA_OUT) &&
> + uio->uio_iov->iov_base)
> + dma_free(uio->uio_iov->iov_base, uio->uio_iov->iov_len);
> +
> + s = splbio();
> + if (uio && uio->uio_iov)
> + pool_put(&sd->mds.mdd_crypto.sr_iovpl, uio->uio_iov);
> + if (uio)
> + pool_put(&sd->mds.mdd_crypto.sr_uiopl, uio);
> + splx(s);
> +
> + return (NULL);
> +}
> +
> +void *
> +sr_crypto_putcryptop(struct cryptop *crp)
> +{
> + struct uio *uio = crp->crp_buf;
> + struct sr_workunit *wu = crp->crp_opaque;
> + struct sr_discipline *sd = wu->swu_dis;
> + int s;
> +
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_putcryptop crp: %p\n",
> + DEVNAME(wu->swu_dis->sd_sc), crp);
> +
> + if ((wu->swu_xs->flags & SCSI_DATA_OUT) && uio->uio_iov->iov_base)
> + dma_free(uio->uio_iov->iov_base, uio->uio_iov->iov_len);
> + s = splbio();
> + pool_put(&sd->mds.mdd_crypto.sr_iovpl, uio->uio_iov);
> + pool_put(&sd->mds.mdd_crypto.sr_uiopl, uio);
> + splx(s);
> + crypto_freereq(crp);
> +
> + return (wu);
> +}
> +
> +int
> +sr_crypto_get_kdf(struct bioc_createraid *bc, struct sr_discipline *sd)
> +{
> + int rv = EINVAL;
> + struct sr_crypto_kdfinfo *kdfinfo;
> +
> + if (!(bc->bc_opaque_flags & BIOC_SOIN))
> + return (rv);
> + if (bc->bc_opaque == NULL)
> + return (rv);
> + if (bc->bc_opaque_size < sizeof(*kdfinfo))
> + return (rv);
> +
> + kdfinfo = malloc(bc->bc_opaque_size, M_DEVBUF, M_WAITOK | M_ZERO);
> + if (copyin(bc->bc_opaque, kdfinfo, bc->bc_opaque_size))
> + goto out;
> +
> + if (kdfinfo->len != bc->bc_opaque_size)
> + goto out;
> +
> + /* copy KDF hint to disk meta data */
> + if (kdfinfo->flags & SR_CRYPTOKDF_HINT) {
> + if (sizeof(sd->mds.mdd_crypto.scr_meta->scm_kdfhint) <
> + kdfinfo->genkdf.len)
> + goto out;
> + bcopy(&kdfinfo->genkdf,
> + sd->mds.mdd_crypto.scr_meta->scm_kdfhint,
> + kdfinfo->genkdf.len);
> + }
> +
> + /* copy mask key to run-time meta data */
> + if ((kdfinfo->flags & SR_CRYPTOKDF_KEY)) {
> + if (sizeof(sd->mds.mdd_crypto.scr_maskkey) <
> + sizeof(kdfinfo->maskkey))
> + goto out;
> + bcopy(&kdfinfo->maskkey, sd->mds.mdd_crypto.scr_maskkey,
> + sizeof(kdfinfo->maskkey));
> + }
> +
> + bc->bc_opaque_status = BIOC_SOINOUT_OK;
> + rv = 0;
> +out:
> + explicit_bzero(kdfinfo, bc->bc_opaque_size);
> + free(kdfinfo, M_DEVBUF);
> +
> + return (rv);
> +}
> +
> +int
> +sr_crypto_encrypt(u_char *p, u_char *c, u_char *key, size_t size, int alg)
> +{
> + rijndael_ctx ctx;
> + int i, rv = 1;
> +
> + switch (alg) {
> + case SR_CRYPTOM_AES_ECB_256:
> + if (rijndael_set_key_enc_only(&ctx, key, 256) != 0)
> + goto out;
> + for (i = 0; i < size; i += RIJNDAEL128_BLOCK_LEN)
> + rijndael_encrypt(&ctx, &p[i], &c[i]);
> + rv = 0;
> + break;
> + default:
> + DNPRINTF(SR_D_DIS, "%s: unsupported encryption algorithm %u\n",
> + "softraid", alg);
> + rv = -1;
> + goto out;
> + }
> +
> +out:
> + explicit_bzero(&ctx, sizeof(ctx));
> + return (rv);
> +}
> +
> +int
> +sr_crypto_decrypt(u_char *c, u_char *p, u_char *key, size_t size, int alg)
> +{
> + rijndael_ctx ctx;
> + int i, rv = 1;
> +
> + switch (alg) {
> + case SR_CRYPTOM_AES_ECB_256:
> + if (rijndael_set_key(&ctx, key, 256) != 0)
> + goto out;
> + for (i = 0; i < size; i += RIJNDAEL128_BLOCK_LEN)
> + rijndael_decrypt(&ctx, &c[i], &p[i]);
> + rv = 0;
> + break;
> + default:
> + DNPRINTF(SR_D_DIS, "%s: unsupported encryption algorithm %u\n",
> + "softraid", alg);
> + rv = -1;
> + goto out;
> + }
> +
> +out:
> + explicit_bzero(&ctx, sizeof(ctx));
> + return (rv);
> +}
> +
> +void
> +sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size,
> + u_int8_t *key, int key_size, u_char *check_digest)
> +{
> + u_char check_key[SHA1_DIGEST_LENGTH];
> + HMAC_SHA1_CTX hmacctx;
> + SHA1_CTX shactx;
> +
> + bzero(check_key, sizeof(check_key));
> + bzero(&hmacctx, sizeof(hmacctx));
> + bzero(&shactx, sizeof(shactx));
> +
> + /* k = SHA1(mask_key) */
> + SHA1Init(&shactx);
> + SHA1Update(&shactx, maskkey, maskkey_size);
> + SHA1Final(check_key, &shactx);
> +
> + /* mac = HMAC_SHA1_k(unencrypted key) */
> + HMAC_SHA1_Init(&hmacctx, check_key, sizeof(check_key));
> + HMAC_SHA1_Update(&hmacctx, key, key_size);
> + HMAC_SHA1_Final(check_digest, &hmacctx);
> +
> + explicit_bzero(check_key, sizeof(check_key));
> + explicit_bzero(&hmacctx, sizeof(hmacctx));
> + explicit_bzero(&shactx, sizeof(shactx));
> +}
> +
> +int
> +sr_crypto_decrypt_key(struct sr_discipline *sd)
> +{
> + u_char check_digest[SHA1_DIGEST_LENGTH];
> + int rv = 1;
> +
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_decrypt_key\n", DEVNAME(sd->sd_sc));
> +
> + if (sd->mds.mdd_crypto.scr_meta->scm_check_alg != SR_CRYPTOC_HMAC_SHA1)
> + goto out;
> +
> + if (sr_crypto_decrypt((u_char *)sd->mds.mdd_crypto.scr_meta->scm_key,
> + (u_char *)sd->mds.mdd_crypto.scr_key,
> + sd->mds.mdd_crypto.scr_maskkey, sizeof(sd->mds.mdd_crypto.scr_key),
> + sd->mds.mdd_crypto.scr_meta->scm_mask_alg) == -1)
> + goto out;
> +
> +#ifdef SR_DEBUG0
> + sr_crypto_dumpkeys(sd);
> +#endif
> +
> + /* Check that the key decrypted properly. */
> + sr_crypto_calculate_check_hmac_sha1(sd->mds.mdd_crypto.scr_maskkey,
> + sizeof(sd->mds.mdd_crypto.scr_maskkey),
> + (u_int8_t *)sd->mds.mdd_crypto.scr_key,
> + sizeof(sd->mds.mdd_crypto.scr_key),
> + check_digest);
> + if (memcmp(sd->mds.mdd_crypto.scr_meta->chk_hmac_sha1.sch_mac,
> + check_digest, sizeof(check_digest)) != 0) {
> + explicit_bzero(sd->mds.mdd_crypto.scr_key,
> + sizeof(sd->mds.mdd_crypto.scr_key));
> + goto out;
> + }
> +
> + rv = 0; /* Success */
> +out:
> + /* we don't need the mask key anymore */
> + explicit_bzero(&sd->mds.mdd_crypto.scr_maskkey,
> + sizeof(sd->mds.mdd_crypto.scr_maskkey));
> +
> + explicit_bzero(check_digest, sizeof(check_digest));
> +
> + return rv;
> +}
> +
> +int
> +sr_crypto_create_keys(struct sr_discipline *sd)
> +{
> +
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_create_keys\n",
> + DEVNAME(sd->sd_sc));
> +
> + if (AES_MAXKEYBYTES < sizeof(sd->mds.mdd_crypto.scr_maskkey))
> + return (1);
> +
> + /* XXX allow user to specify */
> + sd->mds.mdd_crypto.scr_meta->scm_alg = SR_CRYPTOA_AES_XTS_256;
> +
> + /* generate crypto keys */
> + arc4random_buf(sd->mds.mdd_crypto.scr_key,
> + sizeof(sd->mds.mdd_crypto.scr_key));
> +
> + /* Mask the disk keys. */
> + sd->mds.mdd_crypto.scr_meta->scm_mask_alg = SR_CRYPTOM_AES_ECB_256;
> + sr_crypto_encrypt((u_char *)sd->mds.mdd_crypto.scr_key,
> + (u_char *)sd->mds.mdd_crypto.scr_meta->scm_key,
> + sd->mds.mdd_crypto.scr_maskkey, sizeof(sd->mds.mdd_crypto.scr_key),
> + sd->mds.mdd_crypto.scr_meta->scm_mask_alg);
> +
> + /* Prepare key decryption check code. */
> + sd->mds.mdd_crypto.scr_meta->scm_check_alg = SR_CRYPTOC_HMAC_SHA1;
> + sr_crypto_calculate_check_hmac_sha1(sd->mds.mdd_crypto.scr_maskkey,
> + sizeof(sd->mds.mdd_crypto.scr_maskkey),
> + (u_int8_t *)sd->mds.mdd_crypto.scr_key,
> + sizeof(sd->mds.mdd_crypto.scr_key),
> + sd->mds.mdd_crypto.scr_meta->chk_hmac_sha1.sch_mac);
> +
> + /* Erase the plaintext disk keys */
> + explicit_bzero(sd->mds.mdd_crypto.scr_key,
> + sizeof(sd->mds.mdd_crypto.scr_key));
> +
> +#ifdef SR_DEBUG0
> + sr_crypto_dumpkeys(sd);
> +#endif
> +
> + sd->mds.mdd_crypto.scr_meta->scm_flags = SR_CRYPTOF_KEY |
> + SR_CRYPTOF_KDFHINT;
> +
> + return (0);
> +}
> +
> +int
> +sr_crypto_change_maskkey(struct sr_discipline *sd,
> + struct sr_crypto_kdfinfo *kdfinfo1, struct sr_crypto_kdfinfo *kdfinfo2)
> +{
> + u_char check_digest[SHA1_DIGEST_LENGTH];
> + u_char *c, *p = NULL;
> + size_t ksz;
> + int rv = 1;
> +
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_change_maskkey\n",
> + DEVNAME(sd->sd_sc));
> +
> + if (sd->mds.mdd_crypto.scr_meta->scm_check_alg != SR_CRYPTOC_HMAC_SHA1)
> + goto out;
> +
> + c = (u_char *)sd->mds.mdd_crypto.scr_meta->scm_key;
> + ksz = sizeof(sd->mds.mdd_crypto.scr_key);
> + p = malloc(ksz, M_DEVBUF, M_WAITOK | M_ZERO);
> + if (p == NULL)
> + goto out;
> +
> + if (sr_crypto_decrypt(c, p, kdfinfo1->maskkey, ksz,
> + sd->mds.mdd_crypto.scr_meta->scm_mask_alg) == -1)
> + goto out;
> +
> +#ifdef SR_DEBUG0
> + sr_crypto_dumpkeys(sd);
> +#endif
> +
> + sr_crypto_calculate_check_hmac_sha1(kdfinfo1->maskkey,
> + sizeof(kdfinfo1->maskkey), p, ksz, check_digest);
> + if (memcmp(sd->mds.mdd_crypto.scr_meta->chk_hmac_sha1.sch_mac,
> + check_digest, sizeof(check_digest)) != 0) {
> + rv = EPERM;
> + goto out;
> + }
> +
> + /* Mask the disk keys. */
> + c = (u_char *)sd->mds.mdd_crypto.scr_meta->scm_key;
> + if (sr_crypto_encrypt(p, c, kdfinfo2->maskkey, ksz,
> + sd->mds.mdd_crypto.scr_meta->scm_mask_alg) == -1)
> + goto out;
> +
> + /* Prepare key decryption check code. */
> + sd->mds.mdd_crypto.scr_meta->scm_check_alg = SR_CRYPTOC_HMAC_SHA1;
> + sr_crypto_calculate_check_hmac_sha1(kdfinfo2->maskkey,
> + sizeof(kdfinfo2->maskkey), (u_int8_t *)sd->mds.mdd_crypto.scr_key,
> + sizeof(sd->mds.mdd_crypto.scr_key), check_digest);
> +
> + /* Copy new encrypted key and HMAC to metadata. */
> + bcopy(check_digest, sd->mds.mdd_crypto.scr_meta->chk_hmac_sha1.sch_mac,
> + sizeof(sd->mds.mdd_crypto.scr_meta->chk_hmac_sha1.sch_mac));
> +
> + rv = 0; /* Success */
> +
> +out:
> + if (p) {
> + explicit_bzero(p, ksz);
> + free(p, M_DEVBUF);
> + }
> +
> + explicit_bzero(check_digest, sizeof(check_digest));
> + explicit_bzero(&kdfinfo1->maskkey, sizeof(kdfinfo1->maskkey));
> + explicit_bzero(&kdfinfo2->maskkey, sizeof(kdfinfo2->maskkey));
> +
> + return (rv);
> +}
> +
> +struct sr_chunk *
> +sr_crypto_create_key_disk(struct sr_discipline *sd, dev_t dev)
> +{
> + struct sr_softc *sc = sd->sd_sc;
> + struct sr_discipline *fakesd = NULL;
> + struct sr_metadata *sm = NULL;
> + struct sr_meta_chunk *km;
> + struct sr_meta_opt_item *omi = NULL;
> + struct sr_chunk *key_disk = NULL;
> + struct disklabel label;
> + struct vnode *vn;
> + char devname[32];
> + int c, part, open = 0;
> +
> + /*
> + * Create a metadata structure on the key disk and store
> + * keying material in the optional metadata.
> + */
> +
> + sr_meta_getdevname(sc, dev, devname, sizeof(devname));
> +
> + /* Make sure chunk is not already in use. */
> + c = sr_chunk_in_use(sc, dev);
> + if (c != BIOC_SDINVALID && c != BIOC_SDOFFLINE) {
> + printf("%s: %s is already in use\n", DEVNAME(sc), devname);
> + goto done;
> + }
> +
> + /* Open device. */
> + if (bdevvp(dev, &vn)) {
> + printf("%s:, sr_create_key_disk: can't allocate vnode\n",
> + DEVNAME(sc));
> + goto done;
> + }
> + if (VOP_OPEN(vn, FREAD | FWRITE, NOCRED, curproc)) {
> + DNPRINTF(SR_D_META,"%s: sr_create_key_disk cannot open %s\n",
> + DEVNAME(sc), devname);
> + vput(vn);
> + goto fail;
> + }
> + open = 1; /* close dev on error */
> +
> + /* Get partition details. */
> + part = DISKPART(dev);
> + if (VOP_IOCTL(vn, DIOCGDINFO, (caddr_t)&label,
> + FREAD, NOCRED, curproc)) {
> + DNPRINTF(SR_D_META, "%s: sr_create_key_disk ioctl failed\n",
> + DEVNAME(sc));
> + VOP_CLOSE(vn, FREAD | FWRITE, NOCRED, curproc);
> + vput(vn);
> + goto fail;
> + }
> + if (label.d_partitions[part].p_fstype != FS_RAID) {
> + printf("%s: %s partition not of type RAID (%d)\n",
> + DEVNAME(sc), devname,
> + label.d_partitions[part].p_fstype);
> + goto fail;
> + }
> +
> + /*
> + * Create and populate chunk metadata.
> + */
> +
> + key_disk = malloc(sizeof(struct sr_chunk), M_DEVBUF, M_WAITOK | M_ZERO);
> + km = &key_disk->src_meta;
> +
> + key_disk->src_dev_mm = dev;
> + key_disk->src_vn = vn;
> + strlcpy(key_disk->src_devname, devname, sizeof(km->scmi.scm_devname));
> + key_disk->src_size = 0;
> +
> + km->scmi.scm_volid = sd->sd_meta->ssdi.ssd_level;
> + km->scmi.scm_chunk_id = 0;
> + km->scmi.scm_size = 0;
> + km->scmi.scm_coerced_size = 0;
> + strlcpy(km->scmi.scm_devname, devname, sizeof(km->scmi.scm_devname));
> + bcopy(&sd->sd_meta->ssdi.ssd_uuid, &km->scmi.scm_uuid,
> + sizeof(struct sr_uuid));
> +
> + sr_checksum(sc, km, &km->scm_checksum,
> + sizeof(struct sr_meta_chunk_invariant));
> +
> + km->scm_status = BIOC_SDONLINE;
> +
> + /*
> + * Create and populate our own discipline and metadata.
> + */
> +
> + sm = malloc(sizeof(struct sr_metadata), M_DEVBUF, M_WAITOK | M_ZERO);
> + sm->ssdi.ssd_magic = SR_MAGIC;
> + sm->ssdi.ssd_version = SR_META_VERSION;
> + sm->ssd_ondisk = 0;
> + sm->ssdi.ssd_vol_flags = 0;
> + bcopy(&sd->sd_meta->ssdi.ssd_uuid, &sm->ssdi.ssd_uuid,
> + sizeof(struct sr_uuid));
> + sm->ssdi.ssd_chunk_no = 1;
> + sm->ssdi.ssd_volid = SR_KEYDISK_VOLID;
> + sm->ssdi.ssd_level = SR_KEYDISK_LEVEL;
> + sm->ssdi.ssd_size = 0;
> + strlcpy(sm->ssdi.ssd_vendor, "OPENBSD", sizeof(sm->ssdi.ssd_vendor));
> + snprintf(sm->ssdi.ssd_product, sizeof(sm->ssdi.ssd_product),
> + "SR %s", "KEYDISK");
> + snprintf(sm->ssdi.ssd_revision, sizeof(sm->ssdi.ssd_revision),
> + "%03d", SR_META_VERSION);
> +
> + fakesd = malloc(sizeof(struct sr_discipline), M_DEVBUF,
> + M_WAITOK | M_ZERO);
> + fakesd->sd_sc = sd->sd_sc;
> + fakesd->sd_meta = sm;
> + fakesd->sd_meta_type = SR_META_F_NATIVE;
> + fakesd->sd_vol_status = BIOC_SVONLINE;
> + strlcpy(fakesd->sd_name, "KEYDISK", sizeof(fakesd->sd_name));
> + SLIST_INIT(&fakesd->sd_meta_opt);
> +
> + /* Add chunk to volume. */
> + fakesd->sd_vol.sv_chunks = malloc(sizeof(struct sr_chunk *), M_DEVBUF,
> + M_WAITOK | M_ZERO);
> + fakesd->sd_vol.sv_chunks[0] = key_disk;
> + SLIST_INIT(&fakesd->sd_vol.sv_chunk_list);
> + SLIST_INSERT_HEAD(&fakesd->sd_vol.sv_chunk_list, key_disk, src_link);
> +
> + /* Generate mask key. */
> + arc4random_buf(sd->mds.mdd_crypto.scr_maskkey,
> + sizeof(sd->mds.mdd_crypto.scr_maskkey));
> +
> + /* Copy mask key to optional metadata area. */
> + sm->ssdi.ssd_opt_no = 1;
> + omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF,
> + M_WAITOK | M_ZERO);
> + omi->omi_om.somi.som_type = SR_OPT_KEYDISK;
> + bcopy(sd->mds.mdd_crypto.scr_maskkey,
> + omi->omi_om.somi.som_meta.smm_keydisk.skm_maskkey,
> + sizeof(omi->omi_om.somi.som_meta.smm_keydisk.skm_maskkey));
> + SLIST_INSERT_HEAD(&fakesd->sd_meta_opt, omi, omi_link);
> +
> + /* Save metadata. */
> + if (sr_meta_save(fakesd, SR_META_DIRTY)) {
> + printf("%s: could not save metadata to %s\n",
> + DEVNAME(sc), devname);
> + goto fail;
> + }
> +
> + goto done;
> +
> +fail:
> + if (key_disk)
> + free(key_disk, M_DEVBUF);
> + key_disk = NULL;
> +
> +done:
> + if (omi)
> + free(omi, M_DEVBUF);
> + if (fakesd && fakesd->sd_vol.sv_chunks)
> + free(fakesd->sd_vol.sv_chunks, M_DEVBUF);
> + if (fakesd)
> + free(fakesd, M_DEVBUF);
> + if (sm)
> + free(sm, M_DEVBUF);
> + if (open) {
> + VOP_CLOSE(vn, FREAD | FWRITE, NOCRED, curproc);
> + vput(vn);
> + }
> +
> + return key_disk;
> +}
> +
> +struct sr_chunk *
> +sr_crypto_read_key_disk(struct sr_discipline *sd, dev_t dev)
> +{
> + struct sr_softc *sc = sd->sd_sc;
> + struct sr_metadata *sm = NULL;
> + struct sr_meta_opt *om;
> + struct sr_chunk *key_disk = NULL;
> + struct disklabel label;
> + struct vnode *vn = NULL;
> + char devname[32];
> + int c, part, open = 0;
> +
> + /*
> + * Load a key disk and load keying material into memory.
> + */
> +
> + sr_meta_getdevname(sc, dev, devname, sizeof(devname));
> +
> + /* Make sure chunk is not already in use. */
> + c = sr_chunk_in_use(sc, dev);
> + if (c != BIOC_SDINVALID && c != BIOC_SDOFFLINE) {
> + printf("%s: %s is already in use\n", DEVNAME(sc), devname);
> + goto done;
> + }
> +
> + /* Open device. */
> + if (bdevvp(dev, &vn)) {
> + printf("%s:, sr_read_key_disk: can't allocate vnode\n",
> + DEVNAME(sc));
> + goto done;
> + }
> + if (VOP_OPEN(vn, FREAD | FWRITE, NOCRED, curproc)) {
> + DNPRINTF(SR_D_META,"%s: sr_read_key_disk cannot open %s\n",
> + DEVNAME(sc), devname);
> + vput(vn);
> + goto done;
> + }
> + open = 1; /* close dev on error */
> +
> + /* Get partition details. */
> + part = DISKPART(dev);
> + if (VOP_IOCTL(vn, DIOCGDINFO, (caddr_t)&label, FREAD,
> + NOCRED, curproc)) {
> + DNPRINTF(SR_D_META, "%s: sr_read_key_disk ioctl failed\n",
> + DEVNAME(sc));
> + VOP_CLOSE(vn, FREAD | FWRITE, NOCRED, curproc);
> + vput(vn);
> + goto done;
> + }
> + if (label.d_partitions[part].p_fstype != FS_RAID) {
> + printf("%s: %s partition not of type RAID (%d)\n",
> + DEVNAME(sc), devname,
> + label.d_partitions[part].p_fstype);
> + goto done;
> + }
> +
> + /*
> + * Read and validate key disk metadata.
> + */
> + sm = malloc(SR_META_SIZE * 512, M_DEVBUF, M_WAITOK | M_ZERO);
> + if (sr_meta_native_read(sd, dev, sm, NULL)) {
> + printf("%s: native bootprobe could not read native "
> + "metadata\n", DEVNAME(sc));
> + goto done;
> + }
> +
> + if (sr_meta_validate(sd, dev, sm, NULL)) {
> + DNPRINTF(SR_D_META, "%s: invalid metadata\n",
> + DEVNAME(sc));
> + goto done;
> + }
> +
> + /* Make sure this is a key disk. */
> + if (sm->ssdi.ssd_level != SR_KEYDISK_LEVEL) {
> + printf("%s: %s is not a key disk\n", DEVNAME(sc), devname);
> + goto done;
> + }
> +
> + /* Construct key disk chunk. */
> + key_disk = malloc(sizeof(struct sr_chunk), M_DEVBUF, M_WAITOK | M_ZERO);
> + key_disk->src_dev_mm = dev;
> + key_disk->src_vn = vn;
> + key_disk->src_size = 0;
> +
> + bcopy((struct sr_meta_chunk *)(sm + 1), &key_disk->src_meta,
> + sizeof(key_disk->src_meta));
> +
> + /* Read mask key from optional metadata. */
> + om = (struct sr_meta_opt *)((u_int8_t *)(sm + 1) +
> + sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
> + for (c = 0; c < sm->ssdi.ssd_opt_no; c++) {
> + if (om->somi.som_type == SR_OPT_KEYDISK) {
> + bcopy(&om->somi.som_meta.smm_keydisk.skm_maskkey,
> + sd->mds.mdd_crypto.scr_maskkey,
> + sizeof(sd->mds.mdd_crypto.scr_maskkey));
> + break;
> + } else if (om->somi.som_type == SR_OPT_CRYPTO) {
> + bcopy(&om->somi.som_meta.smm_crypto,
> + sd->mds.mdd_crypto.scr_maskkey,
> + sizeof(sd->mds.mdd_crypto.scr_maskkey));
> + break;
> + }
> + om++;
> + }
> +
> + open = 0;
> +
> +done:
> + if (sm)
> + free(sm, M_DEVBUF);
> +
> + if (vn && open) {
> + VOP_CLOSE(vn, FREAD, NOCRED, curproc);
> + vput(vn);
> + }
> +
> + return key_disk;
> +}
> +
> +int
> +sr_crypto_alloc_resources(struct sr_discipline *sd)
> +{
> + struct cryptoini cri;
> + u_int num_keys, i;
> +
> + if (!sd)
> + return (EINVAL);
> +
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_alloc_resources\n",
> + DEVNAME(sd->sd_sc));
> +
> + pool_init(&sd->mds.mdd_crypto.sr_uiopl, sizeof(struct uio), 0, 0, 0,
> + "sr_uiopl", NULL);
> + pool_init(&sd->mds.mdd_crypto.sr_iovpl, sizeof(struct iovec), 0, 0, 0,
> + "sr_iovpl", NULL);
> +
> + for (i = 0; i < SR_CRYPTO_MAXKEYS; i++)
> + sd->mds.mdd_crypto.scr_sid[i] = (u_int64_t)-1;
> +
> + if (sr_wu_alloc(sd))
> + return (ENOMEM);
> + if (sr_ccb_alloc(sd))
> + return (ENOMEM);
> + if (sr_crypto_decrypt_key(sd))
> + return (EPERM);
> +
> + bzero(&cri, sizeof(cri));
> + cri.cri_alg = CRYPTO_AES_XTS;
> + switch (sd->mds.mdd_crypto.scr_meta->scm_alg) {
> + case SR_CRYPTOA_AES_XTS_128:
> + cri.cri_klen = 256;
> + break;
> + case SR_CRYPTOA_AES_XTS_256:
> + cri.cri_klen = 512;
> + break;
> + default:
> + return (EINVAL);
> + }
> +
> + /* Allocate a session for every 2^SR_CRYPTO_KEY_BLKSHIFT blocks */
> + num_keys = sd->sd_meta->ssdi.ssd_size >> SR_CRYPTO_KEY_BLKSHIFT;
> + if (num_keys >= SR_CRYPTO_MAXKEYS)
> + return (EFBIG);
> + for (i = 0; i <= num_keys; i++) {
> + cri.cri_key = sd->mds.mdd_crypto.scr_key[i];
> + if (crypto_newsession(&sd->mds.mdd_crypto.scr_sid[i],
> + &cri, 0) != 0) {
> + for (i = 0;
> + sd->mds.mdd_crypto.scr_sid[i] != (u_int64_t)-1;
> + i++) {
> + crypto_freesession(
> + sd->mds.mdd_crypto.scr_sid[i]);
> + sd->mds.mdd_crypto.scr_sid[i] = (u_int64_t)-1;
> + }
> + return (EINVAL);
> + }
> + }
> +
> + sr_hotplug_register(sd, sr_crypto_hotplug);
> +
> + return (0);
> +}
> +
> +int
> +sr_crypto_free_resources(struct sr_discipline *sd)
> +{
> + int rv = EINVAL;
> + u_int i;
> +
> + if (!sd)
> + return (rv);
> +
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_free_resources\n",
> + DEVNAME(sd->sd_sc));
> +
> + if (sd->mds.mdd_crypto.key_disk != NULL) {
> + explicit_bzero(sd->mds.mdd_crypto.key_disk, sizeof
> + sd->mds.mdd_crypto.key_disk);
> + free(sd->mds.mdd_crypto.key_disk, M_DEVBUF);
> + }
> +
> + sr_hotplug_unregister(sd, sr_crypto_hotplug);
> +
> + for (i = 0; sd->mds.mdd_crypto.scr_sid[i] != (u_int64_t)-1; i++) {
> + crypto_freesession(sd->mds.mdd_crypto.scr_sid[i]);
> + sd->mds.mdd_crypto.scr_sid[i] = (u_int64_t)-1;
> + }
> +
> + sr_wu_free(sd);
> + sr_ccb_free(sd);
> +
> + if (sd->mds.mdd_crypto.sr_uiopl.pr_serial != 0)
> + pool_destroy(&sd->mds.mdd_crypto.sr_uiopl);
> + if (sd->mds.mdd_crypto.sr_iovpl.pr_serial != 0)
> + pool_destroy(&sd->mds.mdd_crypto.sr_iovpl);
> +
> + rv = 0;
> + return (rv);
> +}
> +
> +int
> +sr_crypto_ioctl(struct sr_discipline *sd, struct bioc_discipline *bd)
> +{
> + struct sr_crypto_kdfpair kdfpair;
> + struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
> + int size, rv = 1;
> +
> + DNPRINTF(SR_D_IOCTL, "%s: sr_crypto_ioctl %u\n",
> + DEVNAME(sd->sd_sc), bd->bd_cmd);
> +
> + switch (bd->bd_cmd) {
> + case SR_IOCTL_GET_KDFHINT:
> +
> + /* Get KDF hint for userland. */
> + size = sizeof(sd->mds.mdd_crypto.scr_meta->scm_kdfhint);
> + if (bd->bd_data == NULL || bd->bd_size > size)
> + goto bad;
> + if (copyout(sd->mds.mdd_crypto.scr_meta->scm_kdfhint,
> + bd->bd_data, bd->bd_size))
> + goto bad;
> +
> + rv = 0;
> +
> + break;
> +
> + case SR_IOCTL_CHANGE_PASSPHRASE:
> +
> + /* Attempt to change passphrase. */
> +
> + size = sizeof(kdfpair);
> + if (bd->bd_data == NULL || bd->bd_size > size)
> + goto bad;
> + if (copyin(bd->bd_data, &kdfpair, size))
> + goto bad;
> +
> + size = sizeof(kdfinfo1);
> + if (kdfpair.kdfinfo1 == NULL || kdfpair.kdfsize1 > size)
> + goto bad;
> + if (copyin(kdfpair.kdfinfo1, &kdfinfo1, size))
> + goto bad;
> +
> + size = sizeof(kdfinfo2);
> + if (kdfpair.kdfinfo2 == NULL || kdfpair.kdfsize2 > size)
> + goto bad;
> + if (copyin(kdfpair.kdfinfo2, &kdfinfo2, size))
> + goto bad;
> +
> + if (sr_crypto_change_maskkey(sd, &kdfinfo1, &kdfinfo2))
> + goto bad;
> +
> + /* Save metadata to disk. */
> + rv = sr_meta_save(sd, SR_META_DIRTY);
> +
> + break;
> + }
> +
> +bad:
> + explicit_bzero(&kdfpair, sizeof(kdfpair));
> + explicit_bzero(&kdfinfo1, sizeof(kdfinfo1));
> + explicit_bzero(&kdfinfo2, sizeof(&kdfinfo2));
> + return (rv);
> +}
> +
> +int
> +sr_crypto_meta_opt_load(struct sr_discipline *sd, struct sr_meta_opt *om)
> +{
> + int rv = EINVAL;
> +
> + if (om->somi.som_type == SR_OPT_CRYPTO) {
> + sd->mds.mdd_crypto.scr_meta = &om->somi.som_meta.smm_crypto;
> + rv = 0;
> + }
> +
> + return (rv);
> +}
> +
> +int
> +sr_crypto_rw(struct sr_workunit *wu)
> +{
> + struct cryptop *crp;
> + int s, rv = 0;
> +
> + DNPRINTF(SR_D_DIS, "%s: sr_crypto_rw wu: %p\n",
> + DEVNAME(wu->swu_dis->sd_sc), wu);
> +
> + if (wu->swu_xs->flags & SCSI_DATA_OUT) {
> + /* vndencrypt if key */
> + crp = sr_crypto_getcryptop(wu, 1);
> + if (crp == NULL)
> + return (1);
> + crp->crp_callback = sr_crypto_write;
> + crp->crp_opaque = wu;
> + s = splvm();
> + if (crypto_invoke(crp))
> + rv = 1;
> + else
> + rv = crp->crp_etype;
> + splx(s);
> + } else
> + rv = sr_crypto_rw2(wu, NULL);
> +
> + return (rv);
> +}
> +
> +int
> +sr_crypto_write(struct cryptop *crp)
> +{
> + int s;
> + struct sr_workunit *wu = crp->crp_opaque;
> +
> + DNPRINTF(SR_D_INTR, "%s: sr_crypto_write: wu %x xs: %x\n",
> + DEVNAME(wu->swu_dis->sd_sc), wu, wu->swu_xs);
> +
> + if (crp->crp_etype) {
> + /* fail io */
> + ((struct sr_workunit *)(crp->crp_opaque))->swu_xs->error =
> + XS_DRIVER_STUFFUP;
> + s = splbio();
> + sr_crypto_finish_io(crp->crp_opaque);
> + splx(s);
> + }
> +
> + return (sr_crypto_rw2(wu, crp));
> +}
> +
> +int
> +sr_crypto_rw2(struct sr_workunit *wu, struct cryptop *crp)
> +{
> + struct sr_discipline *sd = wu->swu_dis;
> + struct scsi_xfer *xs = wu->swu_xs;
> + struct sr_ccb *ccb;
> + struct uio *uio;
> + int s;
> + daddr64_t blk;
> +
> + if (sr_validate_io(wu, &blk, "sr_crypto_rw2"))
> + goto bad;
> +
> + blk += sd->sd_meta->ssd_data_offset;
> +
> + wu->swu_io_count = 1;
> +
> + ccb = sr_ccb_get(sd);
> + if (!ccb) {
> + /* should never happen but handle more gracefully */
> + printf("%s: %s: too many ccbs queued\n",
> + DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname);
> + goto bad;
> + }
> +
> + ccb->ccb_buf.b_flags = B_CALL | B_PHYS;
> + ccb->ccb_buf.b_iodone = sr_crypto_intr;
> + ccb->ccb_buf.b_blkno = blk;
> + ccb->ccb_buf.b_bcount = xs->datalen;
> + ccb->ccb_buf.b_bufsize = xs->datalen;
> + ccb->ccb_buf.b_resid = xs->datalen;
> +
> + if (xs->flags & SCSI_DATA_IN) {
> + ccb->ccb_buf.b_flags |= B_READ;
> + ccb->ccb_buf.b_data = xs->data;
> + } else {
> + uio = crp->crp_buf;
> + ccb->ccb_buf.b_flags |= B_WRITE;
> + ccb->ccb_buf.b_data = uio->uio_iov->iov_base;
> + ccb->ccb_opaque = crp;
> + }
> +
> + ccb->ccb_buf.b_error = 0;
> + ccb->ccb_buf.b_proc = curproc;
> + ccb->ccb_wu = wu;
> + ccb->ccb_target = 0;
> + ccb->ccb_buf.b_dev = sd->sd_vol.sv_chunks[0]->src_dev_mm;
> + ccb->ccb_buf.b_vp = sd->sd_vol.sv_chunks[0]->src_vn;
> + if ((ccb->ccb_buf.b_flags & B_READ) == 0)
> + ccb->ccb_buf.b_vp->v_numoutput++;
> +
> + LIST_INIT(&ccb->ccb_buf.b_dep);
> +
> + if (wu->swu_cb_active == 1)
> + panic("%s: sr_crypto_rw2", DEVNAME(sd->sd_sc));
> + TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
> +
> + DNPRINTF(SR_D_DIS, "%s: %s: sr_crypto_rw2: b_bcount: %d "
> + "b_blkno: %x b_flags 0x%0x b_data %p\n",
> + DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
> + ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_blkno,
> + ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data);
> +
> + s = splbio();
> +
> + if (sr_check_io_collision(wu))
> + goto queued;
> +
> + sr_raid_startwu(wu);
> +
> +queued:
> + splx(s);
> + return (0);
> +bad:
> + /* wu is unwound by sr_wu_put */
> + if (crp)
> + crp->crp_etype = EINVAL;
> + return (1);
> +}
> +
> +void
> +sr_crypto_intr(struct buf *bp)
> +{
> + struct sr_ccb *ccb = (struct sr_ccb *)bp;
> + struct sr_workunit *wu = ccb->ccb_wu, *wup;
> + struct sr_discipline *sd = wu->swu_dis;
> + struct scsi_xfer *xs = wu->swu_xs;
> + struct sr_softc *sc = sd->sd_sc;
> + struct cryptop *crp;
> + int s, s2, pend;
> +
> + DNPRINTF(SR_D_INTR, "%s: sr_crypto_intr bp: %x xs: %x\n",
> + DEVNAME(sc), bp, wu->swu_xs);
> +
> + DNPRINTF(SR_D_INTR, "%s: sr_crypto_intr: b_bcount: %d b_resid: %d"
> + " b_flags: 0x%0x\n", DEVNAME(sc), ccb->ccb_buf.b_bcount,
> + ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags);
> +
> + s = splbio();
> +
> + if (ccb->ccb_buf.b_flags & B_ERROR) {
> + printf("%s: i/o error on block %lld\n", DEVNAME(sc),
> + ccb->ccb_buf.b_blkno);
> + wu->swu_ios_failed++;
> + ccb->ccb_state = SR_CCB_FAILED;
> + if (ccb->ccb_target != -1)
> + sd->sd_set_chunk_state(sd, ccb->ccb_target,
> + BIOC_SDOFFLINE);
> + else
> + panic("%s: invalid target on wu: %p", DEVNAME(sc), wu);
> + } else {
> + ccb->ccb_state = SR_CCB_OK;
> + wu->swu_ios_succeeded++;
> + }
> + wu->swu_ios_complete++;
> +
> + DNPRINTF(SR_D_INTR, "%s: sr_crypto_intr: comp: %d count: %d\n",
> + DEVNAME(sc), wu->swu_ios_complete, wu->swu_io_count);
> +
> + if (wu->swu_ios_complete == wu->swu_io_count) {
> + if (wu->swu_ios_failed == wu->swu_ios_complete)
> + xs->error = XS_DRIVER_STUFFUP;
> + else
> + xs->error = XS_NOERROR;
> +
> + pend = 0;
> + TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
> + if (wu == wup) {
> + TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link);
> + pend = 1;
> +
> + if (wu->swu_collider) {
> + wu->swu_collider->swu_state =
> + SR_WU_INPROGRESS;
> + TAILQ_REMOVE(&sd->sd_wu_defq,
> + wu->swu_collider, swu_link);
> + sr_raid_startwu(wu->swu_collider);
> + }
> + break;
> + }
> + }
> +
> + if (!pend)
> + printf("%s: wu: %p not on pending queue\n",
> + DEVNAME(sc), wu);
> +
> + if ((xs->flags & SCSI_DATA_IN) && (xs->error == XS_NOERROR)) {
> + crp = sr_crypto_getcryptop(wu, 0);
> + if (crp == NULL)
> + panic("sr_crypto_intr: no crypto op");
> + ccb->ccb_opaque = crp;
> + crp->crp_callback = sr_crypto_read;
> + crp->crp_opaque = wu;
> + DNPRINTF(SR_D_INTR, "%s: sr_crypto_intr: crypto_invoke "
> + "%p\n", DEVNAME(sc), crp);
> + s2 = splvm();
> + crypto_invoke(crp);
> + splx(s2);
> + goto done;
> + }
> +
> + sr_crypto_finish_io(wu);
> + }
> +
> +done:
> + splx(s);
> +}
> +
> +void
> +sr_crypto_finish_io(struct sr_workunit *wu)
> +{
> + struct sr_discipline *sd = wu->swu_dis;
> + struct scsi_xfer *xs = wu->swu_xs;
> + struct sr_ccb *ccb;
> +#ifdef SR_DEBUG
> + struct sr_softc *sc = sd->sd_sc;
> +#endif /* SR_DEBUG */
> +
> + splassert(IPL_BIO);
> +
> + DNPRINTF(SR_D_INTR, "%s: sr_crypto_finish_io: wu %x xs: %x\n",
> + DEVNAME(sc), wu, xs);
> +
> + xs->resid = 0;
> +
> + if (wu->swu_cb_active == 1)
> + panic("%s: sr_crypto_finish_io", DEVNAME(sd->sd_sc));
> + TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link) {
> + if (ccb->ccb_opaque == NULL)
> + continue;
> + sr_crypto_putcryptop(ccb->ccb_opaque);
> + }
> +
> + sr_scsi_done(sd, xs);
> +
> + if (sd->sd_sync && sd->sd_wu_pending == 0)
> + wakeup(sd);
> +}
> +
> +int
> +sr_crypto_read(struct cryptop *crp)
> +{
> + int s;
> + struct sr_workunit *wu = crp->crp_opaque;
> +
> + DNPRINTF(SR_D_INTR, "%s: sr_crypto_read: wu %x xs: %x\n",
> + DEVNAME(wu->swu_dis->sd_sc), wu, wu->swu_xs);
> +
> + if (crp->crp_etype)
> + wu->swu_xs->error = XS_DRIVER_STUFFUP;
> +
> + s = splbio();
> + sr_crypto_finish_io(wu);
> + splx(s);
> +
> + return (0);
> +}
> +
> +void
> +sr_crypto_hotplug(struct sr_discipline *sd, struct disk *diskp, int action)
> +{
> + DNPRINTF(SR_D_MISC, "%s: sr_crypto_hotplug: %s %d\n",
> + DEVNAME(sd->sd_sc), diskp->dk_name, action);
> +}
> diff --git dev/softraidvar.h dev/softraidvar.h
> index 6c21b5e..a925199 100644
> --- dev/softraidvar.h
> +++ dev/softraidvar.h
> @@ -383,12 +383,11 @@ struct sr_raid6 {
> /* CRYPTO */
> #define SR_CRYPTO_NOWU 16
> struct sr_crypto {
> + struct mutex scr_mutex;
> + TAILQ_HEAD(,sr_crypto_wu) scr_wus;
> struct sr_meta_crypto *scr_meta;
> struct sr_chunk *key_disk;
>
> - struct pool sr_uiopl;
> - struct pool sr_iovpl;
> -
> /* XXX only keep scr_sid over time */
> u_int8_t scr_key[SR_CRYPTO_MAXKEYS][SR_CRYPTO_KEYBYTES];
> u_int8_t scr_maskkey[SR_CRYPTO_MAXKEYBYTES];
> --
> 1.7.5
>
>
> --
> Do not try to solve all life's problems at once -- learn to dread each
> day as it comes.
> -- Donald Kaul