Home | History | Annotate | Line # | Download | only in dev
cgd.c revision 1.116.10.4
      1  1.116.10.4    martin /* $NetBSD: cgd.c,v 1.116.10.4 2021/12/14 19:05:11 martin Exp $ */
      2         1.1     elric 
      3         1.1     elric /*-
      4         1.1     elric  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5         1.1     elric  * All rights reserved.
      6         1.1     elric  *
      7         1.1     elric  * This code is derived from software contributed to The NetBSD Foundation
      8         1.1     elric  * by Roland C. Dowdeswell.
      9         1.1     elric  *
     10         1.1     elric  * Redistribution and use in source and binary forms, with or without
     11         1.1     elric  * modification, are permitted provided that the following conditions
     12         1.1     elric  * are met:
     13         1.1     elric  * 1. Redistributions of source code must retain the above copyright
     14         1.1     elric  *    notice, this list of conditions and the following disclaimer.
     15         1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16         1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17         1.1     elric  *    documentation and/or other materials provided with the distribution.
     18         1.1     elric  *
     19         1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20         1.1     elric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21         1.1     elric  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22         1.1     elric  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23         1.1     elric  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24         1.1     elric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25         1.1     elric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26         1.1     elric  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27         1.1     elric  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28         1.1     elric  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29         1.1     elric  * POSSIBILITY OF SUCH DAMAGE.
     30         1.1     elric  */
     31         1.1     elric 
     32         1.1     elric #include <sys/cdefs.h>
     33  1.116.10.4    martin __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.116.10.4 2021/12/14 19:05:11 martin Exp $");
     34         1.1     elric 
     35         1.1     elric #include <sys/types.h>
     36         1.1     elric #include <sys/param.h>
     37         1.1     elric #include <sys/systm.h>
     38         1.1     elric #include <sys/proc.h>
     39         1.1     elric #include <sys/errno.h>
     40         1.1     elric #include <sys/buf.h>
     41        1.21      yamt #include <sys/bufq.h>
     42  1.116.10.3    martin #include <sys/kmem.h>
     43        1.74    jruoho #include <sys/module.h>
     44         1.1     elric #include <sys/pool.h>
     45         1.1     elric #include <sys/ioctl.h>
     46         1.1     elric #include <sys/device.h>
     47         1.1     elric #include <sys/disk.h>
     48         1.1     elric #include <sys/disklabel.h>
     49         1.1     elric #include <sys/fcntl.h>
     50        1.71  dholland #include <sys/namei.h> /* for pathbuf */
     51         1.1     elric #include <sys/vnode.h>
     52         1.1     elric #include <sys/conf.h>
     53        1.62  christos #include <sys/syslog.h>
     54  1.116.10.3    martin #include <sys/workqueue.h>
     55  1.116.10.3    martin #include <sys/cpu.h>
     56         1.1     elric 
     57         1.1     elric #include <dev/dkvar.h>
     58         1.1     elric #include <dev/cgdvar.h>
     59         1.1     elric 
     60        1.88   hannken #include <miscfs/specfs/specdev.h> /* for v_rdev */
     61        1.88   hannken 
     62       1.102  christos #include "ioconf.h"
     63       1.102  christos 
     64       1.112     alnsn struct selftest_params {
     65       1.112     alnsn 	const char *alg;
     66       1.112     alnsn 	int blocksize;	/* number of bytes */
     67       1.112     alnsn 	int secsize;
     68       1.112     alnsn 	daddr_t blkno;
     69       1.112     alnsn 	int keylen;	/* number of bits */
     70       1.112     alnsn 	int txtlen;	/* number of bytes */
     71       1.112     alnsn 	const uint8_t *key;
     72       1.112     alnsn 	const uint8_t *ptxt;
     73       1.112     alnsn 	const uint8_t *ctxt;
     74       1.112     alnsn };
     75       1.112     alnsn 
     76         1.1     elric /* Entry Point Functions */
     77         1.1     elric 
     78        1.18   thorpej static dev_type_open(cgdopen);
     79        1.18   thorpej static dev_type_close(cgdclose);
     80        1.18   thorpej static dev_type_read(cgdread);
     81        1.18   thorpej static dev_type_write(cgdwrite);
     82        1.18   thorpej static dev_type_ioctl(cgdioctl);
     83        1.18   thorpej static dev_type_strategy(cgdstrategy);
     84        1.18   thorpej static dev_type_dump(cgddump);
     85        1.18   thorpej static dev_type_size(cgdsize);
     86         1.1     elric 
     87         1.1     elric const struct bdevsw cgd_bdevsw = {
     88        1.84  dholland 	.d_open = cgdopen,
     89        1.84  dholland 	.d_close = cgdclose,
     90        1.84  dholland 	.d_strategy = cgdstrategy,
     91        1.84  dholland 	.d_ioctl = cgdioctl,
     92        1.84  dholland 	.d_dump = cgddump,
     93        1.84  dholland 	.d_psize = cgdsize,
     94        1.89  dholland 	.d_discard = nodiscard,
     95  1.116.10.3    martin 	.d_flag = D_DISK | D_MPSAFE
     96         1.1     elric };
     97         1.1     elric 
     98         1.1     elric const struct cdevsw cgd_cdevsw = {
     99        1.84  dholland 	.d_open = cgdopen,
    100        1.84  dholland 	.d_close = cgdclose,
    101        1.84  dholland 	.d_read = cgdread,
    102        1.84  dholland 	.d_write = cgdwrite,
    103        1.84  dholland 	.d_ioctl = cgdioctl,
    104        1.84  dholland 	.d_stop = nostop,
    105        1.84  dholland 	.d_tty = notty,
    106        1.84  dholland 	.d_poll = nopoll,
    107        1.84  dholland 	.d_mmap = nommap,
    108        1.84  dholland 	.d_kqfilter = nokqfilter,
    109        1.90  dholland 	.d_discard = nodiscard,
    110  1.116.10.3    martin 	.d_flag = D_DISK | D_MPSAFE
    111         1.1     elric };
    112         1.1     elric 
    113       1.112     alnsn /*
    114       1.112     alnsn  * Vector 5 from IEEE 1619/D16 truncated to 64 bytes, blkno 1.
    115       1.112     alnsn  */
    116       1.112     alnsn static const uint8_t selftest_aes_xts_256_ptxt[64] = {
    117       1.112     alnsn 	0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
    118       1.112     alnsn 	0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
    119       1.112     alnsn 	0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
    120       1.112     alnsn 	0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
    121       1.112     alnsn 	0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
    122       1.112     alnsn 	0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
    123       1.112     alnsn 	0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
    124       1.112     alnsn 	0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
    125       1.112     alnsn };
    126       1.112     alnsn 
    127       1.112     alnsn static const uint8_t selftest_aes_xts_256_ctxt[512] = {
    128       1.112     alnsn 	0x26, 0x4d, 0x3c, 0xa8, 0x51, 0x21, 0x94, 0xfe,
    129       1.112     alnsn 	0xc3, 0x12, 0xc8, 0xc9, 0x89, 0x1f, 0x27, 0x9f,
    130       1.112     alnsn 	0xef, 0xdd, 0x60, 0x8d, 0x0c, 0x02, 0x7b, 0x60,
    131       1.112     alnsn 	0x48, 0x3a, 0x3f, 0xa8, 0x11, 0xd6, 0x5e, 0xe5,
    132       1.112     alnsn 	0x9d, 0x52, 0xd9, 0xe4, 0x0e, 0xc5, 0x67, 0x2d,
    133       1.112     alnsn 	0x81, 0x53, 0x2b, 0x38, 0xb6, 0xb0, 0x89, 0xce,
    134       1.112     alnsn 	0x95, 0x1f, 0x0f, 0x9c, 0x35, 0x59, 0x0b, 0x8b,
    135       1.112     alnsn 	0x97, 0x8d, 0x17, 0x52, 0x13, 0xf3, 0x29, 0xbb,
    136       1.112     alnsn };
    137       1.112     alnsn 
    138       1.112     alnsn static const uint8_t selftest_aes_xts_256_key[33] = {
    139       1.112     alnsn 	0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
    140       1.112     alnsn 	0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
    141       1.112     alnsn 	0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
    142       1.112     alnsn 	0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95,
    143       1.112     alnsn 	0
    144       1.112     alnsn };
    145       1.112     alnsn 
    146       1.112     alnsn /*
    147       1.112     alnsn  * Vector 11 from IEEE 1619/D16 truncated to 64 bytes, blkno 0xffff.
    148       1.112     alnsn  */
    149       1.112     alnsn static const uint8_t selftest_aes_xts_512_ptxt[64] = {
    150       1.112     alnsn 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    151       1.112     alnsn 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    152       1.112     alnsn 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    153       1.112     alnsn 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    154       1.112     alnsn 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    155       1.112     alnsn 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
    156       1.112     alnsn 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    157       1.112     alnsn 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
    158       1.112     alnsn };
    159       1.112     alnsn 
    160       1.112     alnsn static const uint8_t selftest_aes_xts_512_ctxt[64] = {
    161       1.112     alnsn 	0x77, 0xa3, 0x12, 0x51, 0x61, 0x8a, 0x15, 0xe6,
    162       1.112     alnsn 	0xb9, 0x2d, 0x1d, 0x66, 0xdf, 0xfe, 0x7b, 0x50,
    163       1.112     alnsn 	0xb5, 0x0b, 0xad, 0x55, 0x23, 0x05, 0xba, 0x02,
    164       1.112     alnsn 	0x17, 0xa6, 0x10, 0x68, 0x8e, 0xff, 0x7e, 0x11,
    165       1.112     alnsn 	0xe1, 0xd0, 0x22, 0x54, 0x38, 0xe0, 0x93, 0x24,
    166       1.112     alnsn 	0x2d, 0x6d, 0xb2, 0x74, 0xfd, 0xe8, 0x01, 0xd4,
    167       1.112     alnsn 	0xca, 0xe0, 0x6f, 0x20, 0x92, 0xc7, 0x28, 0xb2,
    168       1.112     alnsn 	0x47, 0x85, 0x59, 0xdf, 0x58, 0xe8, 0x37, 0xc2,
    169       1.112     alnsn };
    170       1.112     alnsn 
    171       1.112     alnsn static const uint8_t selftest_aes_xts_512_key[65] = {
    172       1.112     alnsn 	0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
    173       1.112     alnsn 	0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
    174       1.112     alnsn 	0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69,
    175       1.112     alnsn 	0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27,
    176       1.112     alnsn 	0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
    177       1.112     alnsn 	0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95,
    178       1.112     alnsn 	0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37,
    179       1.112     alnsn 	0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92,
    180       1.112     alnsn 	0
    181       1.112     alnsn };
    182       1.112     alnsn 
    183       1.112     alnsn const struct selftest_params selftests[] = {
    184       1.112     alnsn 	{
    185       1.112     alnsn 		.alg = "aes-xts",
    186       1.112     alnsn 		.blocksize = 16,
    187       1.112     alnsn 		.secsize = 512,
    188       1.112     alnsn 		.blkno = 1,
    189       1.112     alnsn 		.keylen = 256,
    190       1.112     alnsn 		.txtlen = sizeof(selftest_aes_xts_256_ptxt),
    191       1.112     alnsn 		.key  = selftest_aes_xts_256_key,
    192       1.112     alnsn 		.ptxt = selftest_aes_xts_256_ptxt,
    193       1.112     alnsn 		.ctxt = selftest_aes_xts_256_ctxt
    194       1.112     alnsn 	},
    195       1.112     alnsn 	{
    196       1.112     alnsn 		.alg = "aes-xts",
    197       1.112     alnsn 		.blocksize = 16,
    198       1.112     alnsn 		.secsize = 512,
    199       1.112     alnsn 		.blkno = 0xffff,
    200       1.112     alnsn 		.keylen = 512,
    201       1.112     alnsn 		.txtlen = sizeof(selftest_aes_xts_512_ptxt),
    202       1.112     alnsn 		.key  = selftest_aes_xts_512_key,
    203       1.112     alnsn 		.ptxt = selftest_aes_xts_512_ptxt,
    204       1.112     alnsn 		.ctxt = selftest_aes_xts_512_ctxt
    205       1.112     alnsn 	}
    206       1.112     alnsn };
    207       1.112     alnsn 
    208        1.65    dyoung static int cgd_match(device_t, cfdata_t, void *);
    209        1.65    dyoung static void cgd_attach(device_t, device_t, void *);
    210        1.65    dyoung static int cgd_detach(device_t, int);
    211        1.65    dyoung static struct cgd_softc	*cgd_spawn(int);
    212  1.116.10.3    martin static struct cgd_worker *cgd_create_one_worker(void);
    213  1.116.10.3    martin static void cgd_destroy_one_worker(struct cgd_worker *);
    214  1.116.10.3    martin static struct cgd_worker *cgd_create_worker(void);
    215  1.116.10.3    martin static void cgd_destroy_worker(struct cgd_worker *);
    216        1.65    dyoung static int cgd_destroy(device_t);
    217        1.65    dyoung 
    218         1.1     elric /* Internal Functions */
    219         1.1     elric 
    220        1.99   mlelstv static int	cgd_diskstart(device_t, struct buf *);
    221  1.116.10.3    martin static void	cgd_diskstart2(struct cgd_softc *, struct cgd_xfer *);
    222         1.1     elric static void	cgdiodone(struct buf *);
    223  1.116.10.3    martin static void	cgd_iodone2(struct cgd_softc *, struct cgd_xfer *);
    224  1.116.10.3    martin static void	cgd_enqueue(struct cgd_softc *, struct cgd_xfer *);
    225  1.116.10.3    martin static void	cgd_process(struct work *, void *);
    226       1.108  riastrad static int	cgd_dumpblocks(device_t, void *, daddr_t, int);
    227         1.1     elric 
    228        1.32  christos static int	cgd_ioctl_set(struct cgd_softc *, void *, struct lwp *);
    229        1.65    dyoung static int	cgd_ioctl_clr(struct cgd_softc *, struct lwp *);
    230        1.78  christos static int	cgd_ioctl_get(dev_t, void *, struct lwp *);
    231        1.27  drochner static int	cgdinit(struct cgd_softc *, const char *, struct vnode *,
    232        1.32  christos 			struct lwp *);
    233        1.44  christos static void	cgd_cipher(struct cgd_softc *, void *, void *,
    234         1.1     elric 			   size_t, daddr_t, size_t, int);
    235         1.1     elric 
    236        1.29      yamt static struct dkdriver cgddkdriver = {
    237        1.98   mlelstv         .d_minphys  = minphys,
    238        1.98   mlelstv         .d_open = cgdopen,
    239        1.98   mlelstv         .d_close = cgdclose,
    240        1.98   mlelstv         .d_strategy = cgdstrategy,
    241        1.98   mlelstv         .d_iosize = NULL,
    242        1.99   mlelstv         .d_diskstart = cgd_diskstart,
    243       1.108  riastrad         .d_dumpblocks = cgd_dumpblocks,
    244        1.98   mlelstv         .d_lastclose = NULL
    245        1.29      yamt };
    246        1.29      yamt 
    247        1.65    dyoung CFATTACH_DECL3_NEW(cgd, sizeof(struct cgd_softc),
    248        1.65    dyoung     cgd_match, cgd_attach, cgd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
    249        1.65    dyoung 
    250         1.1     elric /* DIAGNOSTIC and DEBUG definitions */
    251         1.1     elric 
    252         1.1     elric #if defined(CGDDEBUG) && !defined(DEBUG)
    253         1.1     elric #define DEBUG
    254         1.1     elric #endif
    255         1.1     elric 
    256         1.1     elric #ifdef DEBUG
    257         1.1     elric int cgddebug = 0;
    258         1.1     elric 
    259         1.1     elric #define CGDB_FOLLOW	0x1
    260         1.1     elric #define CGDB_IO	0x2
    261         1.1     elric #define CGDB_CRYPTO	0x4
    262         1.1     elric 
    263         1.1     elric #define IFDEBUG(x,y)		if (cgddebug & (x)) y
    264         1.1     elric #define DPRINTF(x,y)		IFDEBUG(x, printf y)
    265         1.1     elric #define DPRINTF_FOLLOW(y)	DPRINTF(CGDB_FOLLOW, y)
    266         1.1     elric 
    267        1.26  drochner static void	hexprint(const char *, void *, int);
    268         1.1     elric 
    269         1.1     elric #else
    270         1.1     elric #define IFDEBUG(x,y)
    271         1.1     elric #define DPRINTF(x,y)
    272         1.1     elric #define DPRINTF_FOLLOW(y)
    273         1.1     elric #endif
    274         1.1     elric 
    275         1.1     elric #ifdef DIAGNOSTIC
    276        1.22     perry #define DIAGPANIC(x)		panic x
    277         1.1     elric #define DIAGCONDPANIC(x,y)	if (x) panic y
    278         1.1     elric #else
    279         1.1     elric #define DIAGPANIC(x)
    280         1.1     elric #define DIAGCONDPANIC(x,y)
    281         1.1     elric #endif
    282         1.1     elric 
    283         1.1     elric /* Global variables */
    284         1.1     elric 
    285  1.116.10.3    martin static kmutex_t cgd_spawning_mtx;
    286  1.116.10.3    martin static kcondvar_t cgd_spawning_cv;
    287  1.116.10.3    martin static bool cgd_spawning;
    288  1.116.10.3    martin static struct cgd_worker *cgd_worker;
    289  1.116.10.3    martin static u_int cgd_refcnt;	/* number of users of cgd_worker */
    290  1.116.10.3    martin 
    291         1.1     elric /* Utility Functions */
    292         1.1     elric 
    293         1.1     elric #define CGDUNIT(x)		DISKUNIT(x)
    294         1.1     elric 
    295        1.65    dyoung /* The code */
    296        1.65    dyoung 
    297  1.116.10.3    martin static int
    298  1.116.10.3    martin cgd_lock(bool intr)
    299         1.1     elric {
    300  1.116.10.3    martin 	int error = 0;
    301         1.1     elric 
    302  1.116.10.3    martin 	mutex_enter(&cgd_spawning_mtx);
    303  1.116.10.3    martin 	while (cgd_spawning) {
    304  1.116.10.3    martin 		if (intr)
    305  1.116.10.3    martin 			error = cv_wait_sig(&cgd_spawning_cv, &cgd_spawning_mtx);
    306  1.116.10.3    martin 		else
    307  1.116.10.3    martin 			cv_wait(&cgd_spawning_cv, &cgd_spawning_mtx);
    308  1.116.10.3    martin 	}
    309  1.116.10.3    martin 	if (error == 0)
    310  1.116.10.3    martin 		cgd_spawning = true;
    311  1.116.10.3    martin 	mutex_exit(&cgd_spawning_mtx);
    312  1.116.10.3    martin 	return error;
    313  1.116.10.3    martin }
    314        1.65    dyoung 
    315  1.116.10.3    martin static void
    316  1.116.10.3    martin cgd_unlock(void)
    317  1.116.10.3    martin {
    318  1.116.10.3    martin 	mutex_enter(&cgd_spawning_mtx);
    319  1.116.10.3    martin 	cgd_spawning = false;
    320  1.116.10.3    martin 	cv_broadcast(&cgd_spawning_cv);
    321  1.116.10.3    martin 	mutex_exit(&cgd_spawning_mtx);
    322  1.116.10.3    martin }
    323  1.116.10.3    martin 
    324  1.116.10.3    martin static struct cgd_softc *
    325  1.116.10.3    martin getcgd_softc(dev_t dev)
    326  1.116.10.3    martin {
    327  1.116.10.3    martin 	return device_lookup_private(&cgd_cd, CGDUNIT(dev));
    328         1.1     elric }
    329         1.1     elric 
    330        1.65    dyoung static int
    331        1.65    dyoung cgd_match(device_t self, cfdata_t cfdata, void *aux)
    332        1.65    dyoung {
    333        1.65    dyoung 
    334        1.65    dyoung 	return 1;
    335        1.65    dyoung }
    336         1.1     elric 
    337         1.1     elric static void
    338        1.65    dyoung cgd_attach(device_t parent, device_t self, void *aux)
    339         1.1     elric {
    340        1.65    dyoung 	struct cgd_softc *sc = device_private(self);
    341         1.1     elric 
    342        1.85     skrll 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO);
    343  1.116.10.3    martin 	cv_init(&sc->sc_cv, "cgdcv");
    344        1.98   mlelstv 	dk_init(&sc->sc_dksc, self, DKTYPE_CGD);
    345        1.65    dyoung 	disk_init(&sc->sc_dksc.sc_dkdev, sc->sc_dksc.sc_xname, &cgddkdriver);
    346        1.70     joerg 
    347        1.98   mlelstv 	if (!pmf_device_register(self, NULL, NULL))
    348       1.107   msaitoh 		aprint_error_dev(self,
    349       1.107   msaitoh 		    "unable to register power management hooks\n");
    350        1.65    dyoung }
    351        1.65    dyoung 
    352        1.65    dyoung 
    353        1.65    dyoung static int
    354        1.65    dyoung cgd_detach(device_t self, int flags)
    355        1.65    dyoung {
    356        1.67    dyoung 	int ret;
    357        1.67    dyoung 	const int pmask = 1 << RAW_PART;
    358        1.65    dyoung 	struct cgd_softc *sc = device_private(self);
    359        1.67    dyoung 	struct dk_softc *dksc = &sc->sc_dksc;
    360        1.67    dyoung 
    361        1.67    dyoung 	if (DK_BUSY(dksc, pmask))
    362        1.67    dyoung 		return EBUSY;
    363        1.65    dyoung 
    364        1.98   mlelstv 	if (DK_ATTACHED(dksc) &&
    365        1.67    dyoung 	    (ret = cgd_ioctl_clr(sc, curlwp)) != 0)
    366        1.67    dyoung 		return ret;
    367        1.65    dyoung 
    368        1.67    dyoung 	disk_destroy(&dksc->sc_dkdev);
    369  1.116.10.3    martin 	cv_destroy(&sc->sc_cv);
    370        1.86  christos 	mutex_destroy(&sc->sc_lock);
    371        1.65    dyoung 
    372        1.67    dyoung 	return 0;
    373         1.1     elric }
    374         1.1     elric 
    375         1.1     elric void
    376         1.1     elric cgdattach(int num)
    377         1.1     elric {
    378  1.116.10.3    martin #ifndef _MODULE
    379        1.65    dyoung 	int error;
    380        1.65    dyoung 
    381  1.116.10.3    martin 	mutex_init(&cgd_spawning_mtx, MUTEX_DEFAULT, IPL_NONE);
    382  1.116.10.3    martin 	cv_init(&cgd_spawning_cv, "cgspwn");
    383  1.116.10.3    martin 
    384        1.65    dyoung 	error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
    385        1.65    dyoung 	if (error != 0)
    386        1.65    dyoung 		aprint_error("%s: unable to register cfattach\n",
    387        1.65    dyoung 		    cgd_cd.cd_name);
    388  1.116.10.3    martin #endif
    389        1.65    dyoung }
    390        1.65    dyoung 
    391        1.65    dyoung static struct cgd_softc *
    392        1.65    dyoung cgd_spawn(int unit)
    393        1.65    dyoung {
    394        1.65    dyoung 	cfdata_t cf;
    395  1.116.10.3    martin 	struct cgd_worker *cw;
    396  1.116.10.3    martin 	struct cgd_softc *sc;
    397        1.65    dyoung 
    398  1.116.10.3    martin 	cf = kmem_alloc(sizeof(*cf), KM_SLEEP);
    399        1.65    dyoung 	cf->cf_name = cgd_cd.cd_name;
    400        1.65    dyoung 	cf->cf_atname = cgd_cd.cd_name;
    401        1.65    dyoung 	cf->cf_unit = unit;
    402        1.65    dyoung 	cf->cf_fstate = FSTATE_STAR;
    403        1.65    dyoung 
    404  1.116.10.3    martin 	cw = cgd_create_one_worker();
    405  1.116.10.3    martin 	if (cw == NULL) {
    406  1.116.10.3    martin 		kmem_free(cf, sizeof(*cf));
    407  1.116.10.3    martin 		return NULL;
    408  1.116.10.3    martin 	}
    409  1.116.10.3    martin 
    410  1.116.10.3    martin 	sc = device_private(config_attach_pseudo(cf));
    411  1.116.10.3    martin 	if (sc == NULL) {
    412  1.116.10.3    martin 		cgd_destroy_one_worker(cw);
    413  1.116.10.3    martin 		return NULL;
    414  1.116.10.3    martin 	}
    415  1.116.10.3    martin 
    416  1.116.10.3    martin 	sc->sc_worker = cw;
    417  1.116.10.3    martin 
    418  1.116.10.3    martin 	return sc;
    419        1.65    dyoung }
    420        1.65    dyoung 
    421        1.65    dyoung static int
    422        1.65    dyoung cgd_destroy(device_t dev)
    423        1.65    dyoung {
    424  1.116.10.3    martin 	struct cgd_softc *sc = device_private(dev);
    425  1.116.10.3    martin 	struct cgd_worker *cw = sc->sc_worker;
    426        1.65    dyoung 	cfdata_t cf;
    427  1.116.10.3    martin 	int error;
    428         1.1     elric 
    429        1.65    dyoung 	cf = device_cfdata(dev);
    430        1.65    dyoung 	error = config_detach(dev, DETACH_QUIET);
    431        1.65    dyoung 	if (error)
    432        1.65    dyoung 		return error;
    433  1.116.10.3    martin 
    434  1.116.10.3    martin 	cgd_destroy_one_worker(cw);
    435  1.116.10.3    martin 
    436  1.116.10.3    martin 	kmem_free(cf, sizeof(*cf));
    437        1.65    dyoung 	return 0;
    438         1.1     elric }
    439         1.1     elric 
    440  1.116.10.3    martin static void
    441  1.116.10.3    martin cgd_busy(struct cgd_softc *sc)
    442  1.116.10.3    martin {
    443  1.116.10.3    martin 
    444  1.116.10.3    martin 	mutex_enter(&sc->sc_lock);
    445  1.116.10.3    martin 	while (sc->sc_busy)
    446  1.116.10.3    martin 		cv_wait(&sc->sc_cv, &sc->sc_lock);
    447  1.116.10.3    martin 	sc->sc_busy = true;
    448  1.116.10.3    martin 	mutex_exit(&sc->sc_lock);
    449  1.116.10.3    martin }
    450  1.116.10.3    martin 
    451  1.116.10.3    martin static void
    452  1.116.10.3    martin cgd_unbusy(struct cgd_softc *sc)
    453  1.116.10.3    martin {
    454  1.116.10.3    martin 
    455  1.116.10.3    martin 	mutex_enter(&sc->sc_lock);
    456  1.116.10.3    martin 	sc->sc_busy = false;
    457  1.116.10.3    martin 	cv_broadcast(&sc->sc_cv);
    458  1.116.10.3    martin 	mutex_exit(&sc->sc_lock);
    459  1.116.10.3    martin }
    460  1.116.10.3    martin 
    461  1.116.10.3    martin static struct cgd_worker *
    462  1.116.10.3    martin cgd_create_one_worker(void)
    463  1.116.10.3    martin {
    464  1.116.10.3    martin 	KASSERT(cgd_spawning);
    465  1.116.10.3    martin 
    466  1.116.10.3    martin 	if (cgd_refcnt++ == 0) {
    467  1.116.10.3    martin 		KASSERT(cgd_worker == NULL);
    468  1.116.10.3    martin 		cgd_worker = cgd_create_worker();
    469  1.116.10.3    martin 	}
    470  1.116.10.3    martin 
    471  1.116.10.3    martin 	KASSERT(cgd_worker != NULL);
    472  1.116.10.3    martin 	return cgd_worker;
    473  1.116.10.3    martin }
    474  1.116.10.3    martin 
    475  1.116.10.3    martin static void
    476  1.116.10.3    martin cgd_destroy_one_worker(struct cgd_worker *cw)
    477  1.116.10.3    martin {
    478  1.116.10.3    martin 	KASSERT(cgd_spawning);
    479  1.116.10.3    martin 	KASSERT(cw == cgd_worker);
    480  1.116.10.3    martin 
    481  1.116.10.3    martin 	if (--cgd_refcnt == 0) {
    482  1.116.10.3    martin 		cgd_destroy_worker(cgd_worker);
    483  1.116.10.3    martin 		cgd_worker = NULL;
    484  1.116.10.3    martin 	}
    485  1.116.10.3    martin }
    486  1.116.10.3    martin 
    487  1.116.10.3    martin static struct cgd_worker *
    488  1.116.10.3    martin cgd_create_worker(void)
    489  1.116.10.3    martin {
    490  1.116.10.3    martin 	struct cgd_worker *cw;
    491  1.116.10.3    martin 	struct workqueue *wq;
    492  1.116.10.3    martin 	struct pool *cp;
    493  1.116.10.3    martin 	int error;
    494  1.116.10.3    martin 
    495  1.116.10.3    martin 	cw = kmem_alloc(sizeof(struct cgd_worker), KM_SLEEP);
    496  1.116.10.3    martin 	cp = kmem_alloc(sizeof(struct pool), KM_SLEEP);
    497  1.116.10.3    martin 
    498  1.116.10.3    martin 	error = workqueue_create(&wq, "cgd", cgd_process, NULL,
    499  1.116.10.3    martin 	                         PRI_BIO, IPL_BIO, WQ_MPSAFE | WQ_PERCPU);
    500  1.116.10.3    martin 	if (error) {
    501  1.116.10.3    martin 		kmem_free(cp, sizeof(struct pool));
    502  1.116.10.3    martin 		kmem_free(cw, sizeof(struct cgd_worker));
    503  1.116.10.3    martin 		return NULL;
    504  1.116.10.3    martin 	}
    505  1.116.10.3    martin 
    506  1.116.10.3    martin 	cw->cw_cpool = cp;
    507  1.116.10.3    martin 	cw->cw_wq = wq;
    508  1.116.10.3    martin 	pool_init(cw->cw_cpool, sizeof(struct cgd_xfer), 0,
    509  1.116.10.3    martin 	    0, 0, "cgdcpl", NULL, IPL_BIO);
    510  1.116.10.3    martin 
    511  1.116.10.3    martin 	mutex_init(&cw->cw_lock, MUTEX_DEFAULT, IPL_BIO);
    512  1.116.10.3    martin 
    513  1.116.10.3    martin 	return cw;
    514  1.116.10.3    martin }
    515  1.116.10.3    martin 
    516  1.116.10.3    martin static void
    517  1.116.10.3    martin cgd_destroy_worker(struct cgd_worker *cw)
    518  1.116.10.3    martin {
    519  1.116.10.4    martin 
    520  1.116.10.4    martin 	/*
    521  1.116.10.4    martin 	 * Wait for all worker threads to complete before destroying
    522  1.116.10.4    martin 	 * the rest of the cgd_worker.
    523  1.116.10.4    martin 	 */
    524  1.116.10.4    martin 	if (cw->cw_wq)
    525  1.116.10.4    martin 		workqueue_destroy(cw->cw_wq);
    526  1.116.10.4    martin 
    527  1.116.10.3    martin 	mutex_destroy(&cw->cw_lock);
    528  1.116.10.3    martin 
    529  1.116.10.3    martin 	if (cw->cw_cpool) {
    530  1.116.10.3    martin 		pool_destroy(cw->cw_cpool);
    531  1.116.10.3    martin 		kmem_free(cw->cw_cpool, sizeof(struct pool));
    532  1.116.10.3    martin 	}
    533  1.116.10.3    martin 
    534  1.116.10.3    martin 	kmem_free(cw, sizeof(struct cgd_worker));
    535  1.116.10.3    martin }
    536  1.116.10.3    martin 
    537        1.18   thorpej static int
    538        1.32  christos cgdopen(dev_t dev, int flags, int fmt, struct lwp *l)
    539         1.1     elric {
    540  1.116.10.3    martin 	struct	cgd_softc *sc;
    541  1.116.10.3    martin 	int error;
    542         1.1     elric 
    543        1.56    cegger 	DPRINTF_FOLLOW(("cgdopen(0x%"PRIx64", %d)\n", dev, flags));
    544  1.116.10.3    martin 
    545  1.116.10.3    martin 	error = cgd_lock(true);
    546  1.116.10.3    martin 	if (error)
    547  1.116.10.3    martin 		return error;
    548  1.116.10.3    martin 	sc = getcgd_softc(dev);
    549  1.116.10.3    martin 	if (sc == NULL)
    550  1.116.10.3    martin 		sc = cgd_spawn(CGDUNIT(dev));
    551  1.116.10.3    martin 	cgd_unlock();
    552  1.116.10.3    martin 	if (sc == NULL)
    553  1.116.10.3    martin 		return ENXIO;
    554  1.116.10.3    martin 
    555  1.116.10.3    martin 	return dk_open(&sc->sc_dksc, dev, flags, fmt, l);
    556         1.1     elric }
    557         1.1     elric 
    558        1.18   thorpej static int
    559        1.32  christos cgdclose(dev_t dev, int flags, int fmt, struct lwp *l)
    560         1.1     elric {
    561  1.116.10.3    martin 	struct	cgd_softc *sc;
    562        1.65    dyoung 	struct	dk_softc *dksc;
    563  1.116.10.3    martin 	int error;
    564         1.1     elric 
    565        1.56    cegger 	DPRINTF_FOLLOW(("cgdclose(0x%"PRIx64", %d)\n", dev, flags));
    566  1.116.10.3    martin 
    567  1.116.10.3    martin 	error = cgd_lock(false);
    568  1.116.10.3    martin 	if (error)
    569        1.65    dyoung 		return error;
    570  1.116.10.3    martin 	sc = getcgd_softc(dev);
    571  1.116.10.3    martin 	if (sc == NULL) {
    572  1.116.10.3    martin 		error = ENXIO;
    573  1.116.10.3    martin 		goto done;
    574  1.116.10.3    martin 	}
    575  1.116.10.3    martin 
    576  1.116.10.3    martin 	dksc = &sc->sc_dksc;
    577  1.116.10.3    martin 	if ((error =  dk_close(dksc, dev, flags, fmt, l)) != 0)
    578  1.116.10.3    martin 		goto done;
    579        1.65    dyoung 
    580        1.98   mlelstv 	if (!DK_ATTACHED(dksc)) {
    581  1.116.10.3    martin 		if ((error = cgd_destroy(sc->sc_dksc.sc_dev)) != 0) {
    582  1.116.10.3    martin 			device_printf(dksc->sc_dev,
    583        1.65    dyoung 			    "unable to detach instance\n");
    584  1.116.10.3    martin 			goto done;
    585        1.65    dyoung 		}
    586        1.65    dyoung 	}
    587  1.116.10.3    martin 
    588  1.116.10.3    martin done:
    589  1.116.10.3    martin 	cgd_unlock();
    590  1.116.10.3    martin 
    591  1.116.10.3    martin 	return error;
    592         1.1     elric }
    593         1.1     elric 
    594        1.18   thorpej static void
    595         1.1     elric cgdstrategy(struct buf *bp)
    596         1.1     elric {
    597  1.116.10.3    martin 	struct	cgd_softc *sc = getcgd_softc(bp->b_dev);
    598         1.1     elric 
    599         1.1     elric 	DPRINTF_FOLLOW(("cgdstrategy(%p): b_bcount = %ld\n", bp,
    600         1.1     elric 	    (long)bp->b_bcount));
    601        1.72  riastrad 
    602        1.72  riastrad 	/*
    603       1.111   mlelstv 	 * Reject unaligned writes.
    604        1.72  riastrad 	 */
    605       1.111   mlelstv 	if (((uintptr_t)bp->b_data & 3) != 0) {
    606        1.72  riastrad 		bp->b_error = EINVAL;
    607       1.111   mlelstv 		goto bail;
    608        1.72  riastrad 	}
    609        1.72  riastrad 
    610  1.116.10.3    martin 	dk_strategy(&sc->sc_dksc, bp);
    611         1.1     elric 	return;
    612       1.111   mlelstv 
    613       1.111   mlelstv bail:
    614       1.111   mlelstv 	bp->b_resid = bp->b_bcount;
    615       1.111   mlelstv 	biodone(bp);
    616       1.111   mlelstv 	return;
    617         1.1     elric }
    618         1.1     elric 
    619        1.18   thorpej static int
    620         1.1     elric cgdsize(dev_t dev)
    621         1.1     elric {
    622  1.116.10.3    martin 	struct cgd_softc *sc = getcgd_softc(dev);
    623         1.1     elric 
    624        1.56    cegger 	DPRINTF_FOLLOW(("cgdsize(0x%"PRIx64")\n", dev));
    625  1.116.10.3    martin 	if (!sc)
    626         1.1     elric 		return -1;
    627  1.116.10.3    martin 	return dk_size(&sc->sc_dksc, dev);
    628         1.1     elric }
    629         1.1     elric 
    630        1.16     elric /*
    631        1.16     elric  * cgd_{get,put}data are functions that deal with getting a buffer
    632  1.116.10.3    martin  * for the new encrypted data.
    633  1.116.10.3    martin  * We can no longer have a buffer per device, we need a buffer per
    634  1.116.10.3    martin  * work queue...
    635        1.16     elric  */
    636        1.16     elric 
    637        1.16     elric static void *
    638  1.116.10.3    martin cgd_getdata(struct cgd_softc *sc, unsigned long size)
    639        1.16     elric {
    640  1.116.10.3    martin 	void *data = NULL;
    641        1.16     elric 
    642  1.116.10.3    martin 	mutex_enter(&sc->sc_lock);
    643  1.116.10.3    martin 	if (!sc->sc_data_used) {
    644  1.116.10.3    martin 		sc->sc_data_used = true;
    645  1.116.10.3    martin 		data = sc->sc_data;
    646        1.16     elric 	}
    647  1.116.10.3    martin 	mutex_exit(&sc->sc_lock);
    648        1.16     elric 
    649        1.16     elric 	if (data)
    650        1.16     elric 		return data;
    651        1.16     elric 
    652  1.116.10.3    martin 	return kmem_intr_alloc(size, KM_NOSLEEP);
    653        1.16     elric }
    654        1.16     elric 
    655         1.1     elric static void
    656  1.116.10.3    martin cgd_putdata(struct cgd_softc *sc, void *data, unsigned long size)
    657        1.16     elric {
    658        1.16     elric 
    659  1.116.10.3    martin 	if (data == sc->sc_data) {
    660  1.116.10.3    martin 		mutex_enter(&sc->sc_lock);
    661  1.116.10.3    martin 		sc->sc_data_used = false;
    662  1.116.10.3    martin 		mutex_exit(&sc->sc_lock);
    663  1.116.10.3    martin 	} else
    664  1.116.10.3    martin 		kmem_intr_free(data, size);
    665        1.16     elric }
    666        1.16     elric 
    667        1.99   mlelstv static int
    668        1.99   mlelstv cgd_diskstart(device_t dev, struct buf *bp)
    669         1.1     elric {
    670  1.116.10.3    martin 	struct	cgd_softc *sc = device_private(dev);
    671  1.116.10.3    martin 	struct	cgd_worker *cw = sc->sc_worker;
    672  1.116.10.3    martin 	struct	dk_softc *dksc = &sc->sc_dksc;
    673       1.105   mlelstv 	struct	disk_geom *dg = &dksc->sc_dkdev.dk_geom;
    674  1.116.10.3    martin 	struct	cgd_xfer *cx;
    675        1.99   mlelstv 	struct	buf *nbp;
    676        1.44  christos 	void *	newaddr;
    677         1.1     elric 	daddr_t	bn;
    678         1.1     elric 
    679        1.99   mlelstv 	DPRINTF_FOLLOW(("cgd_diskstart(%p, %p)\n", dksc, bp));
    680         1.1     elric 
    681        1.99   mlelstv 	bn = bp->b_rawblkno;
    682        1.22     perry 
    683        1.99   mlelstv 	/*
    684        1.99   mlelstv 	 * We attempt to allocate all of our resources up front, so that
    685        1.99   mlelstv 	 * we can fail quickly if they are unavailable.
    686        1.99   mlelstv 	 */
    687  1.116.10.3    martin 	nbp = getiobuf(sc->sc_tvn, false);
    688        1.99   mlelstv 	if (nbp == NULL)
    689        1.99   mlelstv 		return EAGAIN;
    690        1.16     elric 
    691  1.116.10.3    martin 	cx = pool_get(cw->cw_cpool, PR_NOWAIT);
    692  1.116.10.3    martin 	if (cx == NULL) {
    693  1.116.10.3    martin 		putiobuf(nbp);
    694  1.116.10.3    martin 		return EAGAIN;
    695  1.116.10.3    martin 	}
    696  1.116.10.3    martin 
    697  1.116.10.3    martin 	cx->cx_sc = sc;
    698  1.116.10.3    martin 	cx->cx_obp = bp;
    699  1.116.10.3    martin 	cx->cx_nbp = nbp;
    700  1.116.10.3    martin 	cx->cx_srcv = cx->cx_dstv = bp->b_data;
    701  1.116.10.3    martin 	cx->cx_blkno = bn;
    702  1.116.10.3    martin 	cx->cx_secsize = dg->dg_secsize;
    703  1.116.10.3    martin 
    704        1.99   mlelstv 	/*
    705        1.99   mlelstv 	 * If we are writing, then we need to encrypt the outgoing
    706        1.99   mlelstv 	 * block into a new block of memory.
    707        1.99   mlelstv 	 */
    708        1.99   mlelstv 	if ((bp->b_flags & B_READ) == 0) {
    709  1.116.10.3    martin 		newaddr = cgd_getdata(sc, bp->b_bcount);
    710        1.99   mlelstv 		if (!newaddr) {
    711  1.116.10.3    martin 			pool_put(cw->cw_cpool, cx);
    712        1.99   mlelstv 			putiobuf(nbp);
    713        1.99   mlelstv 			return EAGAIN;
    714        1.16     elric 		}
    715  1.116.10.3    martin 
    716  1.116.10.3    martin 		cx->cx_dstv = newaddr;
    717  1.116.10.3    martin 		cx->cx_len = bp->b_bcount;
    718  1.116.10.3    martin 		cx->cx_dir = CGD_CIPHER_ENCRYPT;
    719  1.116.10.3    martin 
    720  1.116.10.3    martin 		cgd_enqueue(sc, cx);
    721  1.116.10.3    martin 		return 0;
    722        1.99   mlelstv 	}
    723         1.1     elric 
    724  1.116.10.3    martin 	cgd_diskstart2(sc, cx);
    725  1.116.10.3    martin 	return 0;
    726  1.116.10.3    martin }
    727  1.116.10.3    martin 
    728  1.116.10.3    martin static void
    729  1.116.10.3    martin cgd_diskstart2(struct cgd_softc *sc, struct cgd_xfer *cx)
    730  1.116.10.3    martin {
    731  1.116.10.3    martin 	struct	vnode *vp;
    732  1.116.10.3    martin 	struct	buf *bp;
    733  1.116.10.3    martin 	struct	buf *nbp;
    734  1.116.10.3    martin 
    735  1.116.10.3    martin 	bp = cx->cx_obp;
    736  1.116.10.3    martin 	nbp = cx->cx_nbp;
    737  1.116.10.3    martin 
    738  1.116.10.3    martin 	nbp->b_data = cx->cx_dstv;
    739        1.99   mlelstv 	nbp->b_flags = bp->b_flags;
    740        1.99   mlelstv 	nbp->b_oflags = bp->b_oflags;
    741        1.99   mlelstv 	nbp->b_cflags = bp->b_cflags;
    742        1.99   mlelstv 	nbp->b_iodone = cgdiodone;
    743        1.99   mlelstv 	nbp->b_proc = bp->b_proc;
    744  1.116.10.3    martin 	nbp->b_blkno = btodb(cx->cx_blkno * cx->cx_secsize);
    745        1.99   mlelstv 	nbp->b_bcount = bp->b_bcount;
    746  1.116.10.3    martin 	nbp->b_private = cx;
    747        1.99   mlelstv 
    748        1.99   mlelstv 	BIO_COPYPRIO(nbp, bp);
    749        1.99   mlelstv 
    750        1.99   mlelstv 	if ((nbp->b_flags & B_READ) == 0) {
    751        1.99   mlelstv 		vp = nbp->b_vp;
    752        1.99   mlelstv 		mutex_enter(vp->v_interlock);
    753        1.99   mlelstv 		vp->v_numoutput++;
    754        1.99   mlelstv 		mutex_exit(vp->v_interlock);
    755        1.17       dbj 	}
    756  1.116.10.3    martin 	VOP_STRATEGY(sc->sc_tvn, nbp);
    757         1.1     elric }
    758         1.1     elric 
    759        1.18   thorpej static void
    760        1.17       dbj cgdiodone(struct buf *nbp)
    761         1.1     elric {
    762  1.116.10.3    martin 	struct	cgd_xfer *cx = nbp->b_private;
    763  1.116.10.3    martin 	struct	buf *obp = cx->cx_obp;
    764  1.116.10.3    martin 	struct	cgd_softc *sc = getcgd_softc(obp->b_dev);
    765  1.116.10.3    martin 	struct	dk_softc *dksc = &sc->sc_dksc;
    766       1.105   mlelstv 	struct	disk_geom *dg = &dksc->sc_dkdev.dk_geom;
    767       1.105   mlelstv 	daddr_t	bn;
    768        1.22     perry 
    769  1.116.10.3    martin 	KDASSERT(sc);
    770         1.1     elric 
    771        1.17       dbj 	DPRINTF_FOLLOW(("cgdiodone(%p)\n", nbp));
    772        1.20      yamt 	DPRINTF(CGDB_IO, ("cgdiodone: bp %p bcount %d resid %d\n",
    773         1.1     elric 	    obp, obp->b_bcount, obp->b_resid));
    774       1.107   msaitoh 	DPRINTF(CGDB_IO, (" dev 0x%"PRIx64", nbp %p bn %" PRId64
    775       1.107   msaitoh 	    " addr %p bcnt %d\n", nbp->b_dev, nbp, nbp->b_blkno, nbp->b_data,
    776       1.107   msaitoh 		nbp->b_bcount));
    777        1.46        ad 	if (nbp->b_error != 0) {
    778        1.46        ad 		obp->b_error = nbp->b_error;
    779        1.62  christos 		DPRINTF(CGDB_IO, ("%s: error %d\n", dksc->sc_xname,
    780        1.62  christos 		    obp->b_error));
    781         1.1     elric 	}
    782         1.1     elric 
    783        1.16     elric 	/* Perform the decryption if we are reading.
    784         1.1     elric 	 *
    785         1.1     elric 	 * Note: use the blocknumber from nbp, since it is what
    786         1.1     elric 	 *       we used to encrypt the blocks.
    787         1.1     elric 	 */
    788         1.1     elric 
    789       1.105   mlelstv 	if (nbp->b_flags & B_READ) {
    790       1.105   mlelstv 		bn = dbtob(nbp->b_blkno) / dg->dg_secsize;
    791  1.116.10.3    martin 
    792  1.116.10.3    martin 		cx->cx_obp     = obp;
    793  1.116.10.3    martin 		cx->cx_nbp     = nbp;
    794  1.116.10.3    martin 		cx->cx_dstv    = obp->b_data;
    795  1.116.10.3    martin 		cx->cx_srcv    = obp->b_data;
    796  1.116.10.3    martin 		cx->cx_len     = obp->b_bcount;
    797  1.116.10.3    martin 		cx->cx_blkno   = bn;
    798  1.116.10.3    martin 		cx->cx_secsize = dg->dg_secsize;
    799  1.116.10.3    martin 		cx->cx_dir     = CGD_CIPHER_DECRYPT;
    800  1.116.10.3    martin 
    801  1.116.10.3    martin 		cgd_enqueue(sc, cx);
    802  1.116.10.3    martin 		return;
    803       1.105   mlelstv 	}
    804         1.1     elric 
    805  1.116.10.3    martin 	cgd_iodone2(sc, cx);
    806  1.116.10.3    martin }
    807  1.116.10.3    martin 
    808  1.116.10.3    martin static void
    809  1.116.10.3    martin cgd_iodone2(struct cgd_softc *sc, struct cgd_xfer *cx)
    810  1.116.10.3    martin {
    811  1.116.10.3    martin 	struct cgd_worker *cw = sc->sc_worker;
    812  1.116.10.3    martin 	struct buf *obp = cx->cx_obp;
    813  1.116.10.3    martin 	struct buf *nbp = cx->cx_nbp;
    814  1.116.10.3    martin 	struct dk_softc *dksc = &sc->sc_dksc;
    815  1.116.10.3    martin 
    816  1.116.10.3    martin 	pool_put(cw->cw_cpool, cx);
    817  1.116.10.3    martin 
    818        1.16     elric 	/* If we allocated memory, free it now... */
    819         1.1     elric 	if (nbp->b_data != obp->b_data)
    820  1.116.10.3    martin 		cgd_putdata(sc, nbp->b_data, nbp->b_bcount);
    821         1.1     elric 
    822        1.33      yamt 	putiobuf(nbp);
    823         1.1     elric 
    824       1.100   mlelstv 	/* Request is complete for whatever reason */
    825       1.100   mlelstv 	obp->b_resid = 0;
    826       1.100   mlelstv 	if (obp->b_error != 0)
    827       1.100   mlelstv 		obp->b_resid = obp->b_bcount;
    828       1.100   mlelstv 
    829        1.99   mlelstv 	dk_done(dksc, obp);
    830       1.101   mlelstv 	dk_start(dksc, NULL);
    831         1.1     elric }
    832         1.1     elric 
    833       1.108  riastrad static int
    834       1.108  riastrad cgd_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk)
    835       1.108  riastrad {
    836       1.108  riastrad 	struct cgd_softc *sc = device_private(dev);
    837       1.108  riastrad 	struct dk_softc *dksc = &sc->sc_dksc;
    838       1.108  riastrad 	struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
    839       1.108  riastrad 	size_t nbytes, blksize;
    840       1.108  riastrad 	void *buf;
    841       1.108  riastrad 	int error;
    842       1.108  riastrad 
    843       1.108  riastrad 	/*
    844       1.108  riastrad 	 * dk_dump gives us units of disklabel sectors.  Everything
    845       1.108  riastrad 	 * else in cgd uses units of diskgeom sectors.  These had
    846       1.108  riastrad 	 * better agree; otherwise we need to figure out how to convert
    847       1.108  riastrad 	 * between them.
    848       1.108  riastrad 	 */
    849       1.108  riastrad 	KASSERTMSG((dg->dg_secsize == dksc->sc_dkdev.dk_label->d_secsize),
    850       1.108  riastrad 	    "diskgeom secsize %"PRIu32" != disklabel secsize %"PRIu32,
    851       1.108  riastrad 	    dg->dg_secsize, dksc->sc_dkdev.dk_label->d_secsize);
    852       1.108  riastrad 	blksize = dg->dg_secsize;
    853       1.108  riastrad 
    854       1.108  riastrad 	/*
    855       1.108  riastrad 	 * Compute the number of bytes in this request, which dk_dump
    856       1.108  riastrad 	 * has `helpfully' converted to a number of blocks for us.
    857       1.108  riastrad 	 */
    858       1.108  riastrad 	nbytes = nblk*blksize;
    859       1.108  riastrad 
    860       1.108  riastrad 	/* Try to acquire a buffer to store the ciphertext.  */
    861  1.116.10.3    martin 	buf = cgd_getdata(sc, nbytes);
    862       1.108  riastrad 	if (buf == NULL)
    863       1.108  riastrad 		/* Out of memory: give up.  */
    864       1.108  riastrad 		return ENOMEM;
    865       1.108  riastrad 
    866       1.108  riastrad 	/* Encrypt the caller's data into the temporary buffer.  */
    867       1.108  riastrad 	cgd_cipher(sc, buf, va, nbytes, blkno, blksize, CGD_CIPHER_ENCRYPT);
    868       1.108  riastrad 
    869       1.108  riastrad 	/* Pass it on to the underlying disk device.  */
    870       1.108  riastrad 	error = bdev_dump(sc->sc_tdev, blkno, buf, nbytes);
    871       1.108  riastrad 
    872       1.108  riastrad 	/* Release the buffer.  */
    873  1.116.10.3    martin 	cgd_putdata(sc, buf, nbytes);
    874       1.108  riastrad 
    875       1.108  riastrad 	/* Return any error from the underlying disk device.  */
    876       1.108  riastrad 	return error;
    877       1.108  riastrad }
    878       1.108  riastrad 
    879         1.1     elric /* XXX: we should probably put these into dksubr.c, mostly */
    880        1.18   thorpej static int
    881        1.40  christos cgdread(dev_t dev, struct uio *uio, int flags)
    882         1.1     elric {
    883  1.116.10.3    martin 	struct	cgd_softc *sc;
    884         1.1     elric 	struct	dk_softc *dksc;
    885         1.1     elric 
    886        1.56    cegger 	DPRINTF_FOLLOW(("cgdread(0x%llx, %p, %d)\n",
    887        1.56    cegger 	    (unsigned long long)dev, uio, flags));
    888  1.116.10.3    martin 	sc = getcgd_softc(dev);
    889  1.116.10.3    martin 	if (sc == NULL)
    890  1.116.10.3    martin 		return ENXIO;
    891  1.116.10.3    martin 	dksc = &sc->sc_dksc;
    892        1.98   mlelstv 	if (!DK_ATTACHED(dksc))
    893         1.1     elric 		return ENXIO;
    894         1.1     elric 	return physio(cgdstrategy, NULL, dev, B_READ, minphys, uio);
    895         1.1     elric }
    896         1.1     elric 
    897         1.1     elric /* XXX: we should probably put these into dksubr.c, mostly */
    898        1.18   thorpej static int
    899        1.40  christos cgdwrite(dev_t dev, struct uio *uio, int flags)
    900         1.1     elric {
    901  1.116.10.3    martin 	struct	cgd_softc *sc;
    902         1.1     elric 	struct	dk_softc *dksc;
    903         1.1     elric 
    904        1.56    cegger 	DPRINTF_FOLLOW(("cgdwrite(0x%"PRIx64", %p, %d)\n", dev, uio, flags));
    905  1.116.10.3    martin 	sc = getcgd_softc(dev);
    906  1.116.10.3    martin 	if (sc == NULL)
    907  1.116.10.3    martin 		return ENXIO;
    908  1.116.10.3    martin 	dksc = &sc->sc_dksc;
    909        1.98   mlelstv 	if (!DK_ATTACHED(dksc))
    910         1.1     elric 		return ENXIO;
    911         1.1     elric 	return physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio);
    912         1.1     elric }
    913         1.1     elric 
    914        1.18   thorpej static int
    915        1.44  christos cgdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    916         1.1     elric {
    917  1.116.10.3    martin 	struct	cgd_softc *sc;
    918         1.1     elric 	struct	dk_softc *dksc;
    919         1.1     elric 	int	part = DISKPART(dev);
    920         1.1     elric 	int	pmask = 1 << part;
    921  1.116.10.3    martin 	int	error;
    922         1.1     elric 
    923        1.56    cegger 	DPRINTF_FOLLOW(("cgdioctl(0x%"PRIx64", %ld, %p, %d, %p)\n",
    924        1.32  christos 	    dev, cmd, data, flag, l));
    925        1.78  christos 
    926         1.1     elric 	switch (cmd) {
    927        1.93  christos 	case CGDIOCGET:
    928        1.93  christos 		return cgd_ioctl_get(dev, data, l);
    929         1.1     elric 	case CGDIOCSET:
    930         1.1     elric 	case CGDIOCCLR:
    931         1.1     elric 		if ((flag & FWRITE) == 0)
    932         1.1     elric 			return EBADF;
    933        1.78  christos 		/* FALLTHROUGH */
    934        1.78  christos 	default:
    935  1.116.10.3    martin 		sc = getcgd_softc(dev);
    936  1.116.10.3    martin 		if (sc == NULL)
    937  1.116.10.3    martin 			return ENXIO;
    938  1.116.10.3    martin 		dksc = &sc->sc_dksc;
    939        1.78  christos 		break;
    940         1.1     elric 	}
    941         1.1     elric 
    942         1.1     elric 	switch (cmd) {
    943         1.1     elric 	case CGDIOCSET:
    944  1.116.10.3    martin 		cgd_busy(sc);
    945        1.98   mlelstv 		if (DK_ATTACHED(dksc))
    946  1.116.10.3    martin 			error = EBUSY;
    947  1.116.10.3    martin 		else
    948  1.116.10.3    martin 			error = cgd_ioctl_set(sc, data, l);
    949  1.116.10.3    martin 		cgd_unbusy(sc);
    950  1.116.10.3    martin 		break;
    951         1.1     elric 	case CGDIOCCLR:
    952  1.116.10.3    martin 		cgd_busy(sc);
    953  1.116.10.3    martin 		if (DK_BUSY(&sc->sc_dksc, pmask))
    954  1.116.10.3    martin 			error = EBUSY;
    955  1.116.10.3    martin 		else
    956  1.116.10.3    martin 			error = cgd_ioctl_clr(sc, l);
    957  1.116.10.3    martin 		cgd_unbusy(sc);
    958  1.116.10.3    martin 		break;
    959       1.114  jdolecek 	case DIOCGCACHE:
    960        1.57       apb 	case DIOCCACHESYNC:
    961  1.116.10.3    martin 		cgd_busy(sc);
    962  1.116.10.3    martin 		if (!DK_ATTACHED(dksc)) {
    963  1.116.10.3    martin 			cgd_unbusy(sc);
    964  1.116.10.3    martin 			error = ENOENT;
    965  1.116.10.3    martin 			break;
    966  1.116.10.3    martin 		}
    967        1.57       apb 		/*
    968        1.57       apb 		 * We pass this call down to the underlying disk.
    969        1.57       apb 		 */
    970  1.116.10.3    martin 		error = VOP_IOCTL(sc->sc_tvn, cmd, data, flag, l->l_cred);
    971  1.116.10.3    martin 		cgd_unbusy(sc);
    972  1.116.10.3    martin 		break;
    973  1.116.10.1    martin 	case DIOCGSECTORALIGN: {
    974  1.116.10.1    martin 		struct disk_sectoralign *dsa = data;
    975  1.116.10.1    martin 
    976  1.116.10.3    martin 		cgd_busy(sc);
    977  1.116.10.3    martin 		if (!DK_ATTACHED(dksc)) {
    978  1.116.10.3    martin 			cgd_unbusy(sc);
    979  1.116.10.3    martin 			error = ENOENT;
    980  1.116.10.3    martin 			break;
    981  1.116.10.3    martin 		}
    982  1.116.10.1    martin 
    983  1.116.10.1    martin 		/* Get the underlying disk's sector alignment.  */
    984  1.116.10.3    martin 		error = VOP_IOCTL(sc->sc_tvn, cmd, data, flag, l->l_cred);
    985  1.116.10.3    martin 		if (error) {
    986  1.116.10.3    martin 			cgd_unbusy(sc);
    987  1.116.10.3    martin 			break;
    988  1.116.10.3    martin 		}
    989  1.116.10.1    martin 
    990  1.116.10.1    martin 		/* Adjust for the disklabel partition if necessary.  */
    991  1.116.10.1    martin 		if (part != RAW_PART) {
    992  1.116.10.1    martin 			struct disklabel *lp = dksc->sc_dkdev.dk_label;
    993  1.116.10.1    martin 			daddr_t offset = lp->d_partitions[part].p_offset;
    994  1.116.10.1    martin 			uint32_t r = offset % dsa->dsa_alignment;
    995  1.116.10.1    martin 
    996  1.116.10.1    martin 			if (r < dsa->dsa_firstaligned)
    997  1.116.10.1    martin 				dsa->dsa_firstaligned = dsa->dsa_firstaligned
    998  1.116.10.1    martin 				    - r;
    999  1.116.10.1    martin 			else
   1000  1.116.10.1    martin 				dsa->dsa_firstaligned = (dsa->dsa_firstaligned
   1001  1.116.10.1    martin 				    + dsa->dsa_alignment) - r;
   1002  1.116.10.1    martin 		}
   1003  1.116.10.3    martin 		cgd_unbusy(sc);
   1004  1.116.10.3    martin 		break;
   1005  1.116.10.1    martin 	}
   1006       1.103  christos 	case DIOCGSTRATEGY:
   1007       1.103  christos 	case DIOCSSTRATEGY:
   1008  1.116.10.3    martin 		if (!DK_ATTACHED(dksc)) {
   1009  1.116.10.3    martin 			error = ENOENT;
   1010  1.116.10.3    martin 			break;
   1011  1.116.10.3    martin 		}
   1012       1.103  christos 		/*FALLTHROUGH*/
   1013         1.1     elric 	default:
   1014  1.116.10.3    martin 		error = dk_ioctl(dksc, dev, cmd, data, flag, l);
   1015  1.116.10.3    martin 		break;
   1016        1.93  christos 	case CGDIOCGET:
   1017        1.93  christos 		KASSERT(0);
   1018  1.116.10.3    martin 		error = EINVAL;
   1019         1.1     elric 	}
   1020  1.116.10.3    martin 
   1021  1.116.10.3    martin 	return error;
   1022         1.1     elric }
   1023         1.1     elric 
   1024        1.18   thorpej static int
   1025        1.44  christos cgddump(dev_t dev, daddr_t blkno, void *va, size_t size)
   1026         1.1     elric {
   1027  1.116.10.3    martin 	struct	cgd_softc *sc;
   1028         1.1     elric 
   1029        1.56    cegger 	DPRINTF_FOLLOW(("cgddump(0x%"PRIx64", %" PRId64 ", %p, %lu)\n",
   1030        1.56    cegger 	    dev, blkno, va, (unsigned long)size));
   1031  1.116.10.3    martin 	sc = getcgd_softc(dev);
   1032  1.116.10.3    martin 	if (sc == NULL)
   1033  1.116.10.3    martin 		return ENXIO;
   1034  1.116.10.3    martin 	return dk_dump(&sc->sc_dksc, dev, blkno, va, size, DK_DUMP_RECURSIVE);
   1035         1.1     elric }
   1036         1.1     elric 
   1037         1.1     elric /*
   1038         1.1     elric  * XXXrcd:
   1039         1.1     elric  *  for now we hardcode the maximum key length.
   1040         1.1     elric  */
   1041         1.1     elric #define MAX_KEYSIZE	1024
   1042         1.1     elric 
   1043        1.53  christos static const struct {
   1044        1.53  christos 	const char *n;
   1045        1.53  christos 	int v;
   1046        1.53  christos 	int d;
   1047        1.53  christos } encblkno[] = {
   1048        1.53  christos 	{ "encblkno",  CGD_CIPHER_CBC_ENCBLKNO8, 1 },
   1049        1.53  christos 	{ "encblkno8", CGD_CIPHER_CBC_ENCBLKNO8, 1 },
   1050        1.53  christos 	{ "encblkno1", CGD_CIPHER_CBC_ENCBLKNO1, 8 },
   1051        1.53  christos };
   1052        1.53  christos 
   1053         1.1     elric /* ARGSUSED */
   1054         1.1     elric static int
   1055  1.116.10.3    martin cgd_ioctl_set(struct cgd_softc *sc, void *data, struct lwp *l)
   1056         1.1     elric {
   1057         1.1     elric 	struct	 cgd_ioctl *ci = data;
   1058         1.1     elric 	struct	 vnode *vp;
   1059         1.1     elric 	int	 ret;
   1060        1.53  christos 	size_t	 i;
   1061        1.43    cbiere 	size_t	 keybytes;			/* key length in bytes */
   1062        1.27  drochner 	const char *cp;
   1063        1.71  dholland 	struct pathbuf *pb;
   1064        1.36  christos 	char	 *inbuf;
   1065  1.116.10.3    martin 	struct dk_softc *dksc = &sc->sc_dksc;
   1066         1.1     elric 
   1067         1.1     elric 	cp = ci->ci_disk;
   1068        1.71  dholland 
   1069        1.71  dholland 	ret = pathbuf_copyin(ci->ci_disk, &pb);
   1070        1.71  dholland 	if (ret != 0) {
   1071        1.71  dholland 		return ret;
   1072        1.71  dholland 	}
   1073        1.71  dholland 	ret = dk_lookup(pb, l, &vp);
   1074        1.71  dholland 	pathbuf_destroy(pb);
   1075        1.71  dholland 	if (ret != 0) {
   1076         1.1     elric 		return ret;
   1077        1.71  dholland 	}
   1078         1.1     elric 
   1079  1.116.10.3    martin 	inbuf = kmem_alloc(MAX_KEYSIZE, KM_SLEEP);
   1080        1.36  christos 
   1081  1.116.10.3    martin 	if ((ret = cgdinit(sc, cp, vp, l)) != 0)
   1082         1.1     elric 		goto bail;
   1083         1.1     elric 
   1084        1.36  christos 	(void)memset(inbuf, 0, MAX_KEYSIZE);
   1085         1.1     elric 	ret = copyinstr(ci->ci_alg, inbuf, 256, NULL);
   1086         1.1     elric 	if (ret)
   1087         1.1     elric 		goto bail;
   1088  1.116.10.3    martin 	sc->sc_cfuncs = cryptfuncs_find(inbuf);
   1089  1.116.10.3    martin 	if (!sc->sc_cfuncs) {
   1090         1.1     elric 		ret = EINVAL;
   1091         1.1     elric 		goto bail;
   1092         1.1     elric 	}
   1093         1.1     elric 
   1094        1.43    cbiere 	(void)memset(inbuf, 0, MAX_KEYSIZE);
   1095        1.36  christos 	ret = copyinstr(ci->ci_ivmethod, inbuf, MAX_KEYSIZE, NULL);
   1096         1.1     elric 	if (ret)
   1097         1.1     elric 		goto bail;
   1098        1.53  christos 
   1099        1.53  christos 	for (i = 0; i < __arraycount(encblkno); i++)
   1100        1.53  christos 		if (strcmp(encblkno[i].n, inbuf) == 0)
   1101        1.53  christos 			break;
   1102        1.53  christos 
   1103        1.53  christos 	if (i == __arraycount(encblkno)) {
   1104         1.1     elric 		ret = EINVAL;
   1105         1.1     elric 		goto bail;
   1106         1.1     elric 	}
   1107         1.1     elric 
   1108        1.15       dan 	keybytes = ci->ci_keylen / 8 + 1;
   1109        1.15       dan 	if (keybytes > MAX_KEYSIZE) {
   1110         1.1     elric 		ret = EINVAL;
   1111         1.1     elric 		goto bail;
   1112         1.1     elric 	}
   1113        1.53  christos 
   1114        1.36  christos 	(void)memset(inbuf, 0, MAX_KEYSIZE);
   1115        1.15       dan 	ret = copyin(ci->ci_key, inbuf, keybytes);
   1116         1.1     elric 	if (ret)
   1117         1.1     elric 		goto bail;
   1118         1.1     elric 
   1119  1.116.10.3    martin 	sc->sc_cdata.cf_blocksize = ci->ci_blocksize;
   1120  1.116.10.3    martin 	sc->sc_cdata.cf_mode = encblkno[i].v;
   1121  1.116.10.3    martin 	sc->sc_cdata.cf_keylen = ci->ci_keylen;
   1122  1.116.10.3    martin 	sc->sc_cdata.cf_priv = sc->sc_cfuncs->cf_init(ci->ci_keylen, inbuf,
   1123  1.116.10.3    martin 	    &sc->sc_cdata.cf_blocksize);
   1124  1.116.10.3    martin 	if (sc->sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE) {
   1125        1.62  christos 	    log(LOG_WARNING, "cgd: Disallowed cipher with blocksize %zu > %u\n",
   1126  1.116.10.3    martin 		sc->sc_cdata.cf_blocksize, CGD_MAXBLOCKSIZE);
   1127  1.116.10.3    martin 	    sc->sc_cdata.cf_priv = NULL;
   1128        1.62  christos 	}
   1129        1.78  christos 
   1130        1.53  christos 	/*
   1131        1.53  christos 	 * The blocksize is supposed to be in bytes. Unfortunately originally
   1132        1.53  christos 	 * it was expressed in bits. For compatibility we maintain encblkno
   1133        1.53  christos 	 * and encblkno8.
   1134        1.53  christos 	 */
   1135  1.116.10.3    martin 	sc->sc_cdata.cf_blocksize /= encblkno[i].d;
   1136        1.97  riastrad 	(void)explicit_memset(inbuf, 0, MAX_KEYSIZE);
   1137  1.116.10.3    martin 	if (!sc->sc_cdata.cf_priv) {
   1138         1.1     elric 		ret = EINVAL;		/* XXX is this the right error? */
   1139         1.1     elric 		goto bail;
   1140         1.1     elric 	}
   1141  1.116.10.3    martin 	kmem_free(inbuf, MAX_KEYSIZE);
   1142         1.1     elric 
   1143        1.80  christos 	bufq_alloc(&dksc->sc_bufq, "fcfs", 0);
   1144        1.16     elric 
   1145  1.116.10.3    martin 	sc->sc_data = kmem_alloc(MAXPHYS, KM_SLEEP);
   1146  1.116.10.3    martin 	sc->sc_data_used = false;
   1147        1.16     elric 
   1148        1.98   mlelstv 	/* Attach the disk. */
   1149        1.98   mlelstv 	dk_attach(dksc);
   1150        1.98   mlelstv 	disk_attach(&dksc->sc_dkdev);
   1151         1.1     elric 
   1152        1.80  christos 	disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
   1153        1.77     elric 
   1154        1.29      yamt 	/* Discover wedges on this disk. */
   1155        1.80  christos 	dkwedge_discover(&dksc->sc_dkdev);
   1156        1.29      yamt 
   1157         1.1     elric 	return 0;
   1158         1.1     elric 
   1159         1.1     elric bail:
   1160  1.116.10.3    martin 	kmem_free(inbuf, MAX_KEYSIZE);
   1161        1.51        ad 	(void)vn_close(vp, FREAD|FWRITE, l->l_cred);
   1162         1.1     elric 	return ret;
   1163         1.1     elric }
   1164         1.1     elric 
   1165         1.1     elric /* ARGSUSED */
   1166         1.1     elric static int
   1167  1.116.10.3    martin cgd_ioctl_clr(struct cgd_softc *sc, struct lwp *l)
   1168         1.1     elric {
   1169  1.116.10.3    martin 	struct	dk_softc *dksc = &sc->sc_dksc;
   1170        1.65    dyoung 
   1171        1.98   mlelstv 	if (!DK_ATTACHED(dksc))
   1172        1.65    dyoung 		return ENXIO;
   1173        1.16     elric 
   1174        1.29      yamt 	/* Delete all of our wedges. */
   1175        1.80  christos 	dkwedge_delall(&dksc->sc_dkdev);
   1176        1.29      yamt 
   1177        1.16     elric 	/* Kill off any queued buffers. */
   1178       1.104   mlelstv 	dk_drain(dksc);
   1179        1.80  christos 	bufq_free(dksc->sc_bufq);
   1180         1.1     elric 
   1181  1.116.10.3    martin 	(void)vn_close(sc->sc_tvn, FREAD|FWRITE, l->l_cred);
   1182  1.116.10.3    martin 	sc->sc_cfuncs->cf_destroy(sc->sc_cdata.cf_priv);
   1183  1.116.10.3    martin 	kmem_free(sc->sc_tpath, sc->sc_tpathlen);
   1184  1.116.10.3    martin 	kmem_free(sc->sc_data, MAXPHYS);
   1185  1.116.10.3    martin 	sc->sc_data_used = false;
   1186        1.98   mlelstv 	dk_detach(dksc);
   1187        1.80  christos 	disk_detach(&dksc->sc_dkdev);
   1188         1.1     elric 
   1189         1.1     elric 	return 0;
   1190         1.1     elric }
   1191         1.1     elric 
   1192         1.1     elric static int
   1193        1.78  christos cgd_ioctl_get(dev_t dev, void *data, struct lwp *l)
   1194        1.78  christos {
   1195  1.116.10.3    martin 	struct cgd_softc *sc;
   1196        1.78  christos 	struct cgd_user *cgu;
   1197  1.116.10.3    martin 	int unit, error;
   1198        1.78  christos 
   1199        1.78  christos 	unit = CGDUNIT(dev);
   1200        1.78  christos 	cgu = (struct cgd_user *)data;
   1201        1.78  christos 
   1202        1.78  christos 	DPRINTF_FOLLOW(("cgd_ioctl_get(0x%"PRIx64", %d, %p, %p)\n",
   1203        1.78  christos 			   dev, unit, data, l));
   1204        1.78  christos 
   1205  1.116.10.3    martin 	/* XXX, we always return this units data, so if cgu_unit is
   1206  1.116.10.3    martin 	 * not -1, that field doesn't match the rest
   1207  1.116.10.3    martin 	 */
   1208        1.78  christos 	if (cgu->cgu_unit == -1)
   1209        1.78  christos 		cgu->cgu_unit = unit;
   1210        1.78  christos 
   1211        1.78  christos 	if (cgu->cgu_unit < 0)
   1212        1.78  christos 		return EINVAL;	/* XXX: should this be ENXIO? */
   1213        1.78  christos 
   1214  1.116.10.3    martin 	error = cgd_lock(false);
   1215  1.116.10.3    martin 	if (error)
   1216  1.116.10.3    martin 		return error;
   1217  1.116.10.3    martin 
   1218  1.116.10.3    martin 	sc = device_lookup_private(&cgd_cd, unit);
   1219  1.116.10.3    martin 	if (sc == NULL || !DK_ATTACHED(&sc->sc_dksc)) {
   1220        1.78  christos 		cgu->cgu_dev = 0;
   1221        1.78  christos 		cgu->cgu_alg[0] = '\0';
   1222        1.78  christos 		cgu->cgu_blocksize = 0;
   1223        1.78  christos 		cgu->cgu_mode = 0;
   1224        1.78  christos 		cgu->cgu_keylen = 0;
   1225        1.78  christos 	}
   1226        1.78  christos 	else {
   1227  1.116.10.3    martin 		mutex_enter(&sc->sc_lock);
   1228  1.116.10.3    martin 		cgu->cgu_dev = sc->sc_tdev;
   1229  1.116.10.3    martin 		strncpy(cgu->cgu_alg, sc->sc_cfuncs->cf_name,
   1230        1.78  christos 		    sizeof(cgu->cgu_alg));
   1231  1.116.10.3    martin 		cgu->cgu_blocksize = sc->sc_cdata.cf_blocksize;
   1232  1.116.10.3    martin 		cgu->cgu_mode = sc->sc_cdata.cf_mode;
   1233  1.116.10.3    martin 		cgu->cgu_keylen = sc->sc_cdata.cf_keylen;
   1234  1.116.10.3    martin 		mutex_exit(&sc->sc_lock);
   1235        1.78  christos 	}
   1236  1.116.10.3    martin 
   1237  1.116.10.3    martin 	cgd_unlock();
   1238        1.78  christos 	return 0;
   1239        1.78  christos }
   1240        1.78  christos 
   1241        1.78  christos static int
   1242  1.116.10.3    martin cgdinit(struct cgd_softc *sc, const char *cpath, struct vnode *vp,
   1243        1.32  christos 	struct lwp *l)
   1244         1.1     elric {
   1245        1.80  christos 	struct	disk_geom *dg;
   1246         1.1     elric 	int	ret;
   1247        1.36  christos 	char	*tmppath;
   1248        1.76  christos 	uint64_t psize;
   1249        1.76  christos 	unsigned secsize;
   1250  1.116.10.3    martin 	struct dk_softc *dksc = &sc->sc_dksc;
   1251         1.1     elric 
   1252  1.116.10.3    martin 	sc->sc_tvn = vp;
   1253  1.116.10.3    martin 	sc->sc_tpath = NULL;
   1254         1.1     elric 
   1255  1.116.10.3    martin 	tmppath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
   1256  1.116.10.3    martin 	ret = copyinstr(cpath, tmppath, MAXPATHLEN, &sc->sc_tpathlen);
   1257         1.1     elric 	if (ret)
   1258         1.1     elric 		goto bail;
   1259  1.116.10.3    martin 	sc->sc_tpath = kmem_alloc(sc->sc_tpathlen, KM_SLEEP);
   1260  1.116.10.3    martin 	memcpy(sc->sc_tpath, tmppath, sc->sc_tpathlen);
   1261         1.1     elric 
   1262  1.116.10.3    martin 	sc->sc_tdev = vp->v_rdev;
   1263         1.1     elric 
   1264        1.76  christos 	if ((ret = getdisksize(vp, &psize, &secsize)) != 0)
   1265         1.1     elric 		goto bail;
   1266         1.1     elric 
   1267        1.76  christos 	if (psize == 0) {
   1268         1.1     elric 		ret = ENODEV;
   1269         1.1     elric 		goto bail;
   1270         1.1     elric 	}
   1271         1.1     elric 
   1272         1.1     elric 	/*
   1273         1.1     elric 	 * XXX here we should probe the underlying device.  If we
   1274         1.1     elric 	 *     are accessing a partition of type RAW_PART, then
   1275         1.1     elric 	 *     we should populate our initial geometry with the
   1276         1.1     elric 	 *     geometry that we discover from the device.
   1277         1.1     elric 	 */
   1278        1.80  christos 	dg = &dksc->sc_dkdev.dk_geom;
   1279        1.80  christos 	memset(dg, 0, sizeof(*dg));
   1280        1.80  christos 	dg->dg_secperunit = psize;
   1281       1.105   mlelstv 	dg->dg_secsize = secsize;
   1282        1.80  christos 	dg->dg_ntracks = 1;
   1283       1.105   mlelstv 	dg->dg_nsectors = 1024 * 1024 / dg->dg_secsize;
   1284        1.80  christos 	dg->dg_ncylinders = dg->dg_secperunit / dg->dg_nsectors;
   1285         1.1     elric 
   1286         1.1     elric bail:
   1287  1.116.10.3    martin 	kmem_free(tmppath, MAXPATHLEN);
   1288  1.116.10.3    martin 	if (ret && sc->sc_tpath)
   1289  1.116.10.3    martin 		kmem_free(sc->sc_tpath, sc->sc_tpathlen);
   1290         1.1     elric 	return ret;
   1291         1.1     elric }
   1292         1.1     elric 
   1293         1.1     elric /*
   1294         1.1     elric  * Our generic cipher entry point.  This takes care of the
   1295         1.1     elric  * IV mode and passes off the work to the specific cipher.
   1296         1.1     elric  * We implement here the IV method ``encrypted block
   1297         1.1     elric  * number''.
   1298        1.22     perry  *
   1299         1.1     elric  * XXXrcd: for now we rely on our own crypto framework defined
   1300         1.1     elric  *         in dev/cgd_crypto.c.  This will change when we
   1301         1.1     elric  *         get a generic kernel crypto framework.
   1302         1.1     elric  */
   1303         1.1     elric 
   1304         1.1     elric static void
   1305        1.25   xtraeme blkno2blkno_buf(char *sbuf, daddr_t blkno)
   1306         1.1     elric {
   1307         1.1     elric 	int	i;
   1308         1.1     elric 
   1309         1.1     elric 	/* Set up the blkno in blkno_buf, here we do not care much
   1310         1.1     elric 	 * about the final layout of the information as long as we
   1311         1.1     elric 	 * can guarantee that each sector will have a different IV
   1312         1.1     elric 	 * and that the endianness of the machine will not affect
   1313         1.1     elric 	 * the representation that we have chosen.
   1314         1.1     elric 	 *
   1315         1.1     elric 	 * We choose this representation, because it does not rely
   1316         1.1     elric 	 * on the size of buf (which is the blocksize of the cipher),
   1317         1.1     elric 	 * but allows daddr_t to grow without breaking existing
   1318         1.1     elric 	 * disks.
   1319         1.1     elric 	 *
   1320         1.1     elric 	 * Note that blkno2blkno_buf does not take a size as input,
   1321         1.1     elric 	 * and hence must be called on a pre-zeroed buffer of length
   1322         1.1     elric 	 * greater than or equal to sizeof(daddr_t).
   1323         1.1     elric 	 */
   1324         1.1     elric 	for (i=0; i < sizeof(daddr_t); i++) {
   1325        1.25   xtraeme 		*sbuf++ = blkno & 0xff;
   1326         1.1     elric 		blkno >>= 8;
   1327         1.1     elric 	}
   1328         1.1     elric }
   1329         1.1     elric 
   1330  1.116.10.3    martin static struct cpu_info *
   1331  1.116.10.3    martin cgd_cpu(struct cgd_softc *sc)
   1332  1.116.10.3    martin {
   1333  1.116.10.3    martin 	struct cgd_worker *cw = sc->sc_worker;
   1334  1.116.10.3    martin 	struct cpu_info *ci = NULL;
   1335  1.116.10.3    martin 	u_int cidx, i;
   1336  1.116.10.3    martin 
   1337  1.116.10.3    martin 	if (cw->cw_busy == 0) {
   1338  1.116.10.3    martin 		cw->cw_last = cpu_index(curcpu());
   1339  1.116.10.3    martin 		return NULL;
   1340  1.116.10.3    martin 	}
   1341  1.116.10.3    martin 
   1342  1.116.10.3    martin 	for (i=0, cidx = cw->cw_last+1; i<maxcpus; ++i, ++cidx) {
   1343  1.116.10.3    martin 		if (cidx >= maxcpus)
   1344  1.116.10.3    martin 			cidx = 0;
   1345  1.116.10.3    martin 		ci = cpu_lookup(cidx);
   1346  1.116.10.3    martin 		if (ci) {
   1347  1.116.10.3    martin 			cw->cw_last = cidx;
   1348  1.116.10.3    martin 			break;
   1349  1.116.10.3    martin 		}
   1350  1.116.10.3    martin 	}
   1351  1.116.10.3    martin 
   1352  1.116.10.3    martin 	return ci;
   1353  1.116.10.3    martin }
   1354  1.116.10.3    martin 
   1355  1.116.10.3    martin static void
   1356  1.116.10.3    martin cgd_enqueue(struct cgd_softc *sc, struct cgd_xfer *cx)
   1357  1.116.10.3    martin {
   1358  1.116.10.3    martin 	struct cgd_worker *cw = sc->sc_worker;
   1359  1.116.10.3    martin 	struct cpu_info *ci;
   1360  1.116.10.3    martin 
   1361  1.116.10.3    martin 	mutex_enter(&cw->cw_lock);
   1362  1.116.10.3    martin 	ci = cgd_cpu(sc);
   1363  1.116.10.3    martin 	cw->cw_busy++;
   1364  1.116.10.3    martin 	mutex_exit(&cw->cw_lock);
   1365  1.116.10.3    martin 
   1366  1.116.10.3    martin 	workqueue_enqueue(cw->cw_wq, &cx->cx_work, ci);
   1367  1.116.10.3    martin }
   1368  1.116.10.3    martin 
   1369  1.116.10.3    martin static void
   1370  1.116.10.3    martin cgd_process(struct work *wk, void *arg)
   1371  1.116.10.3    martin {
   1372  1.116.10.3    martin 	struct cgd_xfer *cx = (struct cgd_xfer *)wk;
   1373  1.116.10.3    martin 	struct cgd_softc *sc = cx->cx_sc;
   1374  1.116.10.3    martin 	struct cgd_worker *cw = sc->sc_worker;
   1375  1.116.10.3    martin 
   1376  1.116.10.3    martin 	cgd_cipher(sc, cx->cx_dstv, cx->cx_srcv, cx->cx_len,
   1377  1.116.10.3    martin 	    cx->cx_blkno, cx->cx_secsize, cx->cx_dir);
   1378  1.116.10.3    martin 
   1379  1.116.10.3    martin 	if (cx->cx_dir == CGD_CIPHER_ENCRYPT) {
   1380  1.116.10.3    martin 		cgd_diskstart2(sc, cx);
   1381  1.116.10.3    martin 	} else {
   1382  1.116.10.3    martin 		cgd_iodone2(sc, cx);
   1383  1.116.10.3    martin 	}
   1384  1.116.10.3    martin 
   1385  1.116.10.3    martin 	mutex_enter(&cw->cw_lock);
   1386  1.116.10.3    martin 	if (cw->cw_busy > 0)
   1387  1.116.10.3    martin 		cw->cw_busy--;
   1388  1.116.10.3    martin 	mutex_exit(&cw->cw_lock);
   1389  1.116.10.3    martin }
   1390  1.116.10.3    martin 
   1391         1.1     elric static void
   1392  1.116.10.3    martin cgd_cipher(struct cgd_softc *sc, void *dstv, void *srcv,
   1393        1.44  christos     size_t len, daddr_t blkno, size_t secsize, int dir)
   1394         1.1     elric {
   1395        1.44  christos 	char		*dst = dstv;
   1396       1.112     alnsn 	char		*src = srcv;
   1397  1.116.10.3    martin 	cfunc_cipher_prep	*ciprep = sc->sc_cfuncs->cf_cipher_prep;
   1398  1.116.10.3    martin 	cfunc_cipher	*cipher = sc->sc_cfuncs->cf_cipher;
   1399         1.1     elric 	struct uio	dstuio;
   1400         1.1     elric 	struct uio	srcuio;
   1401         1.1     elric 	struct iovec	dstiov[2];
   1402         1.1     elric 	struct iovec	srciov[2];
   1403  1.116.10.3    martin 	size_t		blocksize = sc->sc_cdata.cf_blocksize;
   1404       1.105   mlelstv 	size_t		todo;
   1405       1.112     alnsn 	char		blkno_buf[CGD_MAXBLOCKSIZE], *iv;
   1406         1.1     elric 
   1407         1.1     elric 	DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir));
   1408         1.1     elric 
   1409        1.22     perry 	DIAGCONDPANIC(len % blocksize != 0,
   1410         1.1     elric 	    ("cgd_cipher: len %% blocksize != 0"));
   1411         1.1     elric 
   1412         1.1     elric 	/* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */
   1413         1.1     elric 	DIAGCONDPANIC(sizeof(daddr_t) > blocksize,
   1414         1.1     elric 	    ("cgd_cipher: sizeof(daddr_t) > blocksize"));
   1415         1.1     elric 
   1416       1.112     alnsn 	DIAGCONDPANIC(blocksize > CGD_MAXBLOCKSIZE,
   1417       1.112     alnsn 	    ("cgd_cipher: blocksize > CGD_MAXBLOCKSIZE"));
   1418         1.1     elric 
   1419         1.1     elric 	dstuio.uio_iov = dstiov;
   1420       1.112     alnsn 	dstuio.uio_iovcnt = 1;
   1421         1.1     elric 
   1422         1.1     elric 	srcuio.uio_iov = srciov;
   1423       1.112     alnsn 	srcuio.uio_iovcnt = 1;
   1424         1.1     elric 
   1425       1.105   mlelstv 	for (; len > 0; len -= todo) {
   1426       1.105   mlelstv 		todo = MIN(len, secsize);
   1427       1.105   mlelstv 
   1428       1.112     alnsn 		dstiov[0].iov_base = dst;
   1429       1.112     alnsn 		srciov[0].iov_base = src;
   1430       1.112     alnsn 		dstiov[0].iov_len  = todo;
   1431       1.112     alnsn 		srciov[0].iov_len  = todo;
   1432         1.1     elric 
   1433        1.64  christos 		memset(blkno_buf, 0x0, blocksize);
   1434         1.1     elric 		blkno2blkno_buf(blkno_buf, blkno);
   1435         1.1     elric 		IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf",
   1436        1.64  christos 		    blkno_buf, blocksize));
   1437       1.112     alnsn 
   1438       1.112     alnsn 		/*
   1439       1.112     alnsn 		 * Compute an initial IV. All ciphers
   1440       1.112     alnsn 		 * can convert blkno_buf in-place.
   1441       1.112     alnsn 		 */
   1442       1.112     alnsn 		iv = blkno_buf;
   1443  1.116.10.3    martin 		ciprep(sc->sc_cdata.cf_priv, iv, blkno_buf, blocksize, dir);
   1444       1.112     alnsn 		IFDEBUG(CGDB_CRYPTO, hexprint("step 2: iv", iv, blocksize));
   1445       1.112     alnsn 
   1446  1.116.10.3    martin 		cipher(sc->sc_cdata.cf_priv, &dstuio, &srcuio, iv, dir);
   1447         1.1     elric 
   1448       1.105   mlelstv 		dst += todo;
   1449       1.105   mlelstv 		src += todo;
   1450         1.1     elric 		blkno++;
   1451         1.1     elric 	}
   1452         1.1     elric }
   1453         1.1     elric 
   1454         1.1     elric #ifdef DEBUG
   1455         1.1     elric static void
   1456        1.26  drochner hexprint(const char *start, void *buf, int len)
   1457         1.1     elric {
   1458         1.1     elric 	char	*c = buf;
   1459         1.1     elric 
   1460         1.1     elric 	DIAGCONDPANIC(len < 0, ("hexprint: called with len < 0"));
   1461         1.1     elric 	printf("%s: len=%06d 0x", start, len);
   1462         1.1     elric 	while (len--)
   1463        1.43    cbiere 		printf("%02x", (unsigned char) *c++);
   1464         1.1     elric }
   1465         1.1     elric #endif
   1466        1.58      haad 
   1467       1.112     alnsn static void
   1468       1.112     alnsn selftest(void)
   1469       1.112     alnsn {
   1470  1.116.10.3    martin 	struct cgd_softc sc;
   1471       1.112     alnsn 	void *buf;
   1472       1.112     alnsn 
   1473       1.112     alnsn 	printf("running cgd selftest ");
   1474       1.112     alnsn 
   1475       1.112     alnsn 	for (size_t i = 0; i < __arraycount(selftests); i++) {
   1476       1.112     alnsn 		const char *alg = selftests[i].alg;
   1477       1.112     alnsn 		const uint8_t *key = selftests[i].key;
   1478       1.112     alnsn 		int keylen = selftests[i].keylen;
   1479       1.112     alnsn 		int txtlen = selftests[i].txtlen;
   1480       1.112     alnsn 
   1481       1.112     alnsn 		printf("%s-%d ", alg, keylen);
   1482       1.112     alnsn 
   1483  1.116.10.3    martin 		memset(&sc, 0, sizeof(sc));
   1484       1.112     alnsn 
   1485  1.116.10.3    martin 		sc.sc_cfuncs = cryptfuncs_find(alg);
   1486  1.116.10.3    martin 		if (sc.sc_cfuncs == NULL)
   1487       1.112     alnsn 			panic("%s not implemented", alg);
   1488       1.112     alnsn 
   1489  1.116.10.3    martin 		sc.sc_cdata.cf_blocksize = 8 * selftests[i].blocksize;
   1490  1.116.10.3    martin 		sc.sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO1;
   1491  1.116.10.3    martin 		sc.sc_cdata.cf_keylen = keylen;
   1492  1.116.10.3    martin 
   1493  1.116.10.3    martin 		sc.sc_cdata.cf_priv = sc.sc_cfuncs->cf_init(keylen,
   1494  1.116.10.3    martin 		    key, &sc.sc_cdata.cf_blocksize);
   1495  1.116.10.3    martin 		if (sc.sc_cdata.cf_priv == NULL)
   1496       1.112     alnsn 			panic("cf_priv is NULL");
   1497  1.116.10.3    martin 		if (sc.sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE)
   1498  1.116.10.3    martin 			panic("bad block size %zu", sc.sc_cdata.cf_blocksize);
   1499       1.112     alnsn 
   1500  1.116.10.3    martin 		sc.sc_cdata.cf_blocksize /= 8;
   1501       1.112     alnsn 
   1502  1.116.10.3    martin 		buf = kmem_alloc(txtlen, KM_SLEEP);
   1503       1.112     alnsn 		memcpy(buf, selftests[i].ptxt, txtlen);
   1504       1.112     alnsn 
   1505  1.116.10.3    martin 		cgd_cipher(&sc, buf, buf, txtlen, selftests[i].blkno,
   1506       1.112     alnsn 				selftests[i].secsize, CGD_CIPHER_ENCRYPT);
   1507       1.112     alnsn 		if (memcmp(buf, selftests[i].ctxt, txtlen) != 0)
   1508       1.112     alnsn 			panic("encryption is broken");
   1509       1.112     alnsn 
   1510  1.116.10.3    martin 		cgd_cipher(&sc, buf, buf, txtlen, selftests[i].blkno,
   1511       1.112     alnsn 				selftests[i].secsize, CGD_CIPHER_DECRYPT);
   1512       1.112     alnsn 		if (memcmp(buf, selftests[i].ptxt, txtlen) != 0)
   1513       1.112     alnsn 			panic("decryption is broken");
   1514       1.112     alnsn 
   1515  1.116.10.3    martin 		kmem_free(buf, txtlen);
   1516  1.116.10.3    martin 		sc.sc_cfuncs->cf_destroy(sc.sc_cdata.cf_priv);
   1517       1.112     alnsn 	}
   1518       1.112     alnsn 
   1519       1.112     alnsn 	printf("done\n");
   1520       1.112     alnsn }
   1521       1.112     alnsn 
   1522       1.116  pgoyette MODULE(MODULE_CLASS_DRIVER, cgd, "blowfish,des,dk_subr,bufq_fcfs");
   1523        1.74    jruoho 
   1524        1.58      haad #ifdef _MODULE
   1525        1.66    dyoung CFDRIVER_DECL(cgd, DV_DISK, NULL);
   1526       1.109  pgoyette 
   1527       1.109  pgoyette devmajor_t cgd_bmajor = -1, cgd_cmajor = -1;
   1528        1.74    jruoho #endif
   1529        1.58      haad 
   1530        1.58      haad static int
   1531        1.58      haad cgd_modcmd(modcmd_t cmd, void *arg)
   1532        1.58      haad {
   1533        1.82    martin 	int error = 0;
   1534        1.74    jruoho 
   1535        1.58      haad 	switch (cmd) {
   1536        1.58      haad 	case MODULE_CMD_INIT:
   1537       1.112     alnsn 		selftest();
   1538        1.74    jruoho #ifdef _MODULE
   1539  1.116.10.3    martin 		mutex_init(&cgd_spawning_mtx, MUTEX_DEFAULT, IPL_NONE);
   1540  1.116.10.3    martin 		cv_init(&cgd_spawning_cv, "cgspwn");
   1541  1.116.10.3    martin 
   1542        1.66    dyoung 		error = config_cfdriver_attach(&cgd_cd);
   1543        1.66    dyoung 		if (error)
   1544        1.66    dyoung 			break;
   1545        1.66    dyoung 
   1546        1.66    dyoung 		error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
   1547        1.66    dyoung 	        if (error) {
   1548        1.66    dyoung 			config_cfdriver_detach(&cgd_cd);
   1549       1.109  pgoyette 			aprint_error("%s: unable to register cfattach for"
   1550       1.109  pgoyette 			    "%s, error %d\n", __func__, cgd_cd.cd_name, error);
   1551        1.66    dyoung 			break;
   1552        1.66    dyoung 		}
   1553       1.109  pgoyette 		/*
   1554       1.109  pgoyette 		 * Attach the {b,c}devsw's
   1555       1.109  pgoyette 		 */
   1556       1.109  pgoyette 		error = devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
   1557       1.109  pgoyette 		    &cgd_cdevsw, &cgd_cmajor);
   1558        1.74    jruoho 
   1559       1.109  pgoyette 		/*
   1560       1.109  pgoyette 		 * If devsw_attach fails, remove from autoconf database
   1561       1.109  pgoyette 		 */
   1562        1.66    dyoung 		if (error) {
   1563        1.66    dyoung 			config_cfattach_detach(cgd_cd.cd_name, &cgd_ca);
   1564        1.66    dyoung 			config_cfdriver_detach(&cgd_cd);
   1565       1.109  pgoyette 			aprint_error("%s: unable to attach %s devsw, "
   1566       1.109  pgoyette 			    "error %d", __func__, cgd_cd.cd_name, error);
   1567        1.66    dyoung 			break;
   1568        1.66    dyoung 		}
   1569        1.74    jruoho #endif
   1570        1.58      haad 		break;
   1571        1.58      haad 
   1572        1.58      haad 	case MODULE_CMD_FINI:
   1573        1.74    jruoho #ifdef _MODULE
   1574       1.109  pgoyette 		/*
   1575       1.109  pgoyette 		 * Remove {b,c}devsw's
   1576       1.109  pgoyette 		 */
   1577       1.109  pgoyette 		devsw_detach(&cgd_bdevsw, &cgd_cdevsw);
   1578       1.109  pgoyette 
   1579       1.109  pgoyette 		/*
   1580       1.109  pgoyette 		 * Now remove device from autoconf database
   1581       1.109  pgoyette 		 */
   1582        1.66    dyoung 		error = config_cfattach_detach(cgd_cd.cd_name, &cgd_ca);
   1583       1.109  pgoyette 		if (error) {
   1584       1.110  pgoyette 			(void)devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
   1585       1.109  pgoyette 			    &cgd_cdevsw, &cgd_cmajor);
   1586       1.109  pgoyette 			aprint_error("%s: failed to detach %s cfattach, "
   1587       1.109  pgoyette 			    "error %d\n", __func__, cgd_cd.cd_name, error);
   1588       1.109  pgoyette  			break;
   1589       1.109  pgoyette 		}
   1590       1.109  pgoyette 		error = config_cfdriver_detach(&cgd_cd);
   1591       1.109  pgoyette 		if (error) {
   1592       1.110  pgoyette 			(void)config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
   1593       1.110  pgoyette 			(void)devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
   1594       1.109  pgoyette 			    &cgd_cdevsw, &cgd_cmajor);
   1595       1.109  pgoyette 			aprint_error("%s: failed to detach %s cfdriver, "
   1596       1.109  pgoyette 			    "error %d\n", __func__, cgd_cd.cd_name, error);
   1597        1.66    dyoung 			break;
   1598       1.109  pgoyette 		}
   1599  1.116.10.3    martin 
   1600  1.116.10.3    martin 		cv_destroy(&cgd_spawning_cv);
   1601  1.116.10.3    martin 		mutex_destroy(&cgd_spawning_mtx);
   1602        1.74    jruoho #endif
   1603        1.58      haad 		break;
   1604        1.58      haad 
   1605        1.58      haad 	case MODULE_CMD_STAT:
   1606       1.109  pgoyette 		error = ENOTTY;
   1607       1.109  pgoyette 		break;
   1608        1.58      haad 	default:
   1609       1.109  pgoyette 		error = ENOTTY;
   1610       1.109  pgoyette 		break;
   1611        1.58      haad 	}
   1612        1.58      haad 
   1613        1.58      haad 	return error;
   1614        1.58      haad }
   1615