xref: /netbsd-src/sys/dev/cgd.c (revision 7c69fd1390e15771240722f7800b3a39ab7fbd8c)
1*7c69fd13Sriastradh /* $NetBSD: cgd.c,v 1.146 2022/04/02 09:53:20 riastradh Exp $ */
24366a007Selric 
34366a007Selric /*-
44366a007Selric  * Copyright (c) 2002 The NetBSD Foundation, Inc.
54366a007Selric  * All rights reserved.
64366a007Selric  *
74366a007Selric  * This code is derived from software contributed to The NetBSD Foundation
84366a007Selric  * by Roland C. Dowdeswell.
94366a007Selric  *
104366a007Selric  * Redistribution and use in source and binary forms, with or without
114366a007Selric  * modification, are permitted provided that the following conditions
124366a007Selric  * are met:
134366a007Selric  * 1. Redistributions of source code must retain the above copyright
144366a007Selric  *    notice, this list of conditions and the following disclaimer.
154366a007Selric  * 2. Redistributions in binary form must reproduce the above copyright
164366a007Selric  *    notice, this list of conditions and the following disclaimer in the
174366a007Selric  *    documentation and/or other materials provided with the distribution.
184366a007Selric  *
194366a007Selric  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
204366a007Selric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
214366a007Selric  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
224366a007Selric  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
234366a007Selric  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
244366a007Selric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254366a007Selric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264366a007Selric  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
274366a007Selric  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284366a007Selric  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
294366a007Selric  * POSSIBILITY OF SUCH DAMAGE.
304366a007Selric  */
314366a007Selric 
324366a007Selric #include <sys/cdefs.h>
33*7c69fd13Sriastradh __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.146 2022/04/02 09:53:20 riastradh Exp $");
344366a007Selric 
354366a007Selric #include <sys/types.h>
364366a007Selric #include <sys/param.h>
374366a007Selric #include <sys/buf.h>
3805f25dccSyamt #include <sys/bufq.h>
3978d996a8Sriastradh #include <sys/conf.h>
4078d996a8Sriastradh #include <sys/cpu.h>
414366a007Selric #include <sys/device.h>
424366a007Selric #include <sys/disk.h>
434366a007Selric #include <sys/disklabel.h>
4478d996a8Sriastradh #include <sys/errno.h>
454366a007Selric #include <sys/fcntl.h>
4678d996a8Sriastradh #include <sys/ioctl.h>
4778d996a8Sriastradh #include <sys/kmem.h>
4878d996a8Sriastradh #include <sys/module.h>
498f6ed30dSdholland #include <sys/namei.h> /* for pathbuf */
5078d996a8Sriastradh #include <sys/pool.h>
5178d996a8Sriastradh #include <sys/proc.h>
5218975112Schristos #include <sys/syslog.h>
5378d996a8Sriastradh #include <sys/systm.h>
5478d996a8Sriastradh #include <sys/vnode.h>
55afc6579bSmlelstv #include <sys/workqueue.h>
564366a007Selric 
5778d996a8Sriastradh #include <dev/cgd_crypto.h>
584366a007Selric #include <dev/cgdvar.h>
5978d996a8Sriastradh #include <dev/dkvar.h>
604366a007Selric 
61292a0c7fShannken #include <miscfs/specfs/specdev.h> /* for v_rdev */
62292a0c7fShannken 
63e7ae23fdSchristos #include "ioconf.h"
644366a007Selric 
65b21f21dfSalnsn struct selftest_params {
66b21f21dfSalnsn 	const char *alg;
675b0a15b1Sriastradh 	int encblkno8;
68b21f21dfSalnsn 	int blocksize;	/* number of bytes */
69b21f21dfSalnsn 	int secsize;
70b21f21dfSalnsn 	daddr_t blkno;
71b21f21dfSalnsn 	int keylen;	/* number of bits */
72b21f21dfSalnsn 	int txtlen;	/* number of bytes */
73b21f21dfSalnsn 	const uint8_t *key;
74b21f21dfSalnsn 	const uint8_t *ptxt;
75b21f21dfSalnsn 	const uint8_t *ctxt;
76b21f21dfSalnsn };
77b21f21dfSalnsn 
78e7ae23fdSchristos /* Entry Point Functions */
794366a007Selric 
80a1bb10efSthorpej static dev_type_open(cgdopen);
81a1bb10efSthorpej static dev_type_close(cgdclose);
82a1bb10efSthorpej static dev_type_read(cgdread);
83a1bb10efSthorpej static dev_type_write(cgdwrite);
84a1bb10efSthorpej static dev_type_ioctl(cgdioctl);
85a1bb10efSthorpej static dev_type_strategy(cgdstrategy);
86a1bb10efSthorpej static dev_type_dump(cgddump);
87a1bb10efSthorpej static dev_type_size(cgdsize);
884366a007Selric 
894366a007Selric const struct bdevsw cgd_bdevsw = {
90a68f9396Sdholland 	.d_open = cgdopen,
91a68f9396Sdholland 	.d_close = cgdclose,
92a68f9396Sdholland 	.d_strategy = cgdstrategy,
93a68f9396Sdholland 	.d_ioctl = cgdioctl,
94a68f9396Sdholland 	.d_dump = cgddump,
95a68f9396Sdholland 	.d_psize = cgdsize,
968c70ef39Sdholland 	.d_discard = nodiscard,
97afc6579bSmlelstv 	.d_flag = D_DISK | D_MPSAFE
984366a007Selric };
994366a007Selric 
1004366a007Selric const struct cdevsw cgd_cdevsw = {
101a68f9396Sdholland 	.d_open = cgdopen,
102a68f9396Sdholland 	.d_close = cgdclose,
103a68f9396Sdholland 	.d_read = cgdread,
104a68f9396Sdholland 	.d_write = cgdwrite,
105a68f9396Sdholland 	.d_ioctl = cgdioctl,
106a68f9396Sdholland 	.d_stop = nostop,
107a68f9396Sdholland 	.d_tty = notty,
108a68f9396Sdholland 	.d_poll = nopoll,
109a68f9396Sdholland 	.d_mmap = nommap,
110a68f9396Sdholland 	.d_kqfilter = nokqfilter,
111f9228f42Sdholland 	.d_discard = nodiscard,
112afc6579bSmlelstv 	.d_flag = D_DISK | D_MPSAFE
1134366a007Selric };
1144366a007Selric 
115b21f21dfSalnsn /*
116b21f21dfSalnsn  * Vector 5 from IEEE 1619/D16 truncated to 64 bytes, blkno 1.
117b21f21dfSalnsn  */
118b21f21dfSalnsn static const uint8_t selftest_aes_xts_256_ptxt[64] = {
119b21f21dfSalnsn 	0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
120b21f21dfSalnsn 	0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
121b21f21dfSalnsn 	0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
122b21f21dfSalnsn 	0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
123b21f21dfSalnsn 	0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
124b21f21dfSalnsn 	0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
125b21f21dfSalnsn 	0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
126b21f21dfSalnsn 	0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
127b21f21dfSalnsn };
128b21f21dfSalnsn 
129b21f21dfSalnsn static const uint8_t selftest_aes_xts_256_ctxt[512] = {
130b21f21dfSalnsn 	0x26, 0x4d, 0x3c, 0xa8, 0x51, 0x21, 0x94, 0xfe,
131b21f21dfSalnsn 	0xc3, 0x12, 0xc8, 0xc9, 0x89, 0x1f, 0x27, 0x9f,
132b21f21dfSalnsn 	0xef, 0xdd, 0x60, 0x8d, 0x0c, 0x02, 0x7b, 0x60,
133b21f21dfSalnsn 	0x48, 0x3a, 0x3f, 0xa8, 0x11, 0xd6, 0x5e, 0xe5,
134b21f21dfSalnsn 	0x9d, 0x52, 0xd9, 0xe4, 0x0e, 0xc5, 0x67, 0x2d,
135b21f21dfSalnsn 	0x81, 0x53, 0x2b, 0x38, 0xb6, 0xb0, 0x89, 0xce,
136b21f21dfSalnsn 	0x95, 0x1f, 0x0f, 0x9c, 0x35, 0x59, 0x0b, 0x8b,
137b21f21dfSalnsn 	0x97, 0x8d, 0x17, 0x52, 0x13, 0xf3, 0x29, 0xbb,
138b21f21dfSalnsn };
139b21f21dfSalnsn 
140b21f21dfSalnsn static const uint8_t selftest_aes_xts_256_key[33] = {
141b21f21dfSalnsn 	0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
142b21f21dfSalnsn 	0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
143b21f21dfSalnsn 	0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
144b21f21dfSalnsn 	0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95,
145b21f21dfSalnsn 	0
146b21f21dfSalnsn };
147b21f21dfSalnsn 
148b21f21dfSalnsn /*
149b21f21dfSalnsn  * Vector 11 from IEEE 1619/D16 truncated to 64 bytes, blkno 0xffff.
150b21f21dfSalnsn  */
151b21f21dfSalnsn static const uint8_t selftest_aes_xts_512_ptxt[64] = {
152b21f21dfSalnsn 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
153b21f21dfSalnsn 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
154b21f21dfSalnsn 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
155b21f21dfSalnsn 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
156b21f21dfSalnsn 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
157b21f21dfSalnsn 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
158b21f21dfSalnsn 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
159b21f21dfSalnsn 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
160b21f21dfSalnsn };
161b21f21dfSalnsn 
162b21f21dfSalnsn static const uint8_t selftest_aes_xts_512_ctxt[64] = {
163b21f21dfSalnsn 	0x77, 0xa3, 0x12, 0x51, 0x61, 0x8a, 0x15, 0xe6,
164b21f21dfSalnsn 	0xb9, 0x2d, 0x1d, 0x66, 0xdf, 0xfe, 0x7b, 0x50,
165b21f21dfSalnsn 	0xb5, 0x0b, 0xad, 0x55, 0x23, 0x05, 0xba, 0x02,
166b21f21dfSalnsn 	0x17, 0xa6, 0x10, 0x68, 0x8e, 0xff, 0x7e, 0x11,
167b21f21dfSalnsn 	0xe1, 0xd0, 0x22, 0x54, 0x38, 0xe0, 0x93, 0x24,
168b21f21dfSalnsn 	0x2d, 0x6d, 0xb2, 0x74, 0xfd, 0xe8, 0x01, 0xd4,
169b21f21dfSalnsn 	0xca, 0xe0, 0x6f, 0x20, 0x92, 0xc7, 0x28, 0xb2,
170b21f21dfSalnsn 	0x47, 0x85, 0x59, 0xdf, 0x58, 0xe8, 0x37, 0xc2,
171b21f21dfSalnsn };
172b21f21dfSalnsn 
173b21f21dfSalnsn static const uint8_t selftest_aes_xts_512_key[65] = {
174b21f21dfSalnsn 	0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
175b21f21dfSalnsn 	0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
176b21f21dfSalnsn 	0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69,
177b21f21dfSalnsn 	0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27,
178b21f21dfSalnsn 	0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
179b21f21dfSalnsn 	0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95,
180b21f21dfSalnsn 	0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37,
181b21f21dfSalnsn 	0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92,
182b21f21dfSalnsn 	0
183b21f21dfSalnsn };
184b21f21dfSalnsn 
1857e265cbbSriastradh static const uint8_t selftest_aes_cbc_key[32] = {
1867e265cbbSriastradh 	0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
1877e265cbbSriastradh 	0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
1887e265cbbSriastradh 	0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69,
1897e265cbbSriastradh 	0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27,
1907e265cbbSriastradh };
1917e265cbbSriastradh 
1927e265cbbSriastradh static const uint8_t selftest_aes_cbc_128_ptxt[64] = {
1937e265cbbSriastradh 	0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
1947e265cbbSriastradh 	0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
1957e265cbbSriastradh 	0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
1967e265cbbSriastradh 	0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
1977e265cbbSriastradh 	0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
1987e265cbbSriastradh 	0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
1997e265cbbSriastradh 	0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
2007e265cbbSriastradh 	0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
2017e265cbbSriastradh };
2027e265cbbSriastradh 
2037e265cbbSriastradh static const uint8_t selftest_aes_cbc_128_ctxt[64] = { /* blkno=1 */
2047e265cbbSriastradh 	0x93, 0x94, 0x56, 0x36, 0x83, 0xbc, 0xff, 0xa4,
2057e265cbbSriastradh 	0xe0, 0x24, 0x34, 0x12, 0xbe, 0xfa, 0xb0, 0x7d,
2067e265cbbSriastradh 	0x88, 0x1e, 0xc5, 0x57, 0x55, 0x23, 0x05, 0x0c,
2077e265cbbSriastradh 	0x69, 0xa5, 0xc1, 0xda, 0x64, 0xee, 0x74, 0x10,
2087e265cbbSriastradh 	0xc2, 0xc5, 0xe6, 0x66, 0xd6, 0xa7, 0x49, 0x1c,
2097e265cbbSriastradh 	0x9d, 0x40, 0xb5, 0x0c, 0x9b, 0x6e, 0x1c, 0xe6,
2107e265cbbSriastradh 	0xb1, 0x7a, 0x1c, 0xe7, 0x5a, 0xfe, 0xf9, 0x2a,
2117e265cbbSriastradh 	0x78, 0xfa, 0xb7, 0x7b, 0x08, 0xdf, 0x8e, 0x51,
2127e265cbbSriastradh };
2137e265cbbSriastradh 
2147e265cbbSriastradh static const uint8_t selftest_aes_cbc_256_ptxt[64] = {
2157e265cbbSriastradh 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2167e265cbbSriastradh 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2177e265cbbSriastradh 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2187e265cbbSriastradh 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
2197e265cbbSriastradh 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
2207e265cbbSriastradh 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
2217e265cbbSriastradh 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
2227e265cbbSriastradh 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
2237e265cbbSriastradh };
2247e265cbbSriastradh 
2257e265cbbSriastradh static const uint8_t selftest_aes_cbc_256_ctxt[64] = { /* blkno=0xffff */
2267e265cbbSriastradh 	0x6c, 0xa3, 0x15, 0x17, 0x51, 0x90, 0xe9, 0x69,
2277e265cbbSriastradh 	0x08, 0x36, 0x7b, 0xa6, 0xbb, 0xd1, 0x0b, 0x9e,
2287e265cbbSriastradh 	0xcd, 0x6b, 0x1e, 0xaf, 0xb6, 0x2e, 0x62, 0x7d,
2297e265cbbSriastradh 	0x8e, 0xde, 0xf0, 0xed, 0x0d, 0x44, 0xe7, 0x31,
2307e265cbbSriastradh 	0x26, 0xcf, 0xd5, 0x0b, 0x3e, 0x95, 0x59, 0x89,
2317e265cbbSriastradh 	0xdf, 0x5d, 0xd6, 0x9a, 0x00, 0x66, 0xcc, 0x7f,
2327e265cbbSriastradh 	0x45, 0xd3, 0x06, 0x58, 0xed, 0xef, 0x49, 0x47,
2337e265cbbSriastradh 	0x87, 0x89, 0x17, 0x7d, 0x08, 0x56, 0x50, 0xe1,
2347e265cbbSriastradh };
2357e265cbbSriastradh 
2367e265cbbSriastradh static const uint8_t selftest_3des_cbc_key[24] = {
2377e265cbbSriastradh 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2387e265cbbSriastradh 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2397e265cbbSriastradh 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2407e265cbbSriastradh };
2417e265cbbSriastradh 
2427e265cbbSriastradh static const uint8_t selftest_3des_cbc_ptxt[64] = {
2437e265cbbSriastradh 	0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
2447e265cbbSriastradh 	0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
2457e265cbbSriastradh 	0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
2467e265cbbSriastradh 	0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
2477e265cbbSriastradh 	0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
2487e265cbbSriastradh 	0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
2497e265cbbSriastradh 	0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
2507e265cbbSriastradh 	0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
2517e265cbbSriastradh };
2527e265cbbSriastradh 
2537e265cbbSriastradh static const uint8_t selftest_3des_cbc_ctxt[64] = {
2547e265cbbSriastradh 	0xa2, 0xfe, 0x81, 0xaa, 0x10, 0x6c, 0xea, 0xb9,
2557e265cbbSriastradh 	0x11, 0x58, 0x1f, 0x29, 0xb5, 0x86, 0x71, 0x56,
2567e265cbbSriastradh 	0xe9, 0x25, 0x1d, 0x07, 0xb1, 0x69, 0x59, 0x6c,
2577e265cbbSriastradh 	0x96, 0x80, 0xf7, 0x54, 0x38, 0xaa, 0xa7, 0xe4,
2587e265cbbSriastradh 	0xe8, 0x81, 0xf5, 0x00, 0xbb, 0x1c, 0x00, 0x3c,
2597e265cbbSriastradh 	0xba, 0x38, 0x45, 0x97, 0x4c, 0xcf, 0x84, 0x14,
2607e265cbbSriastradh 	0x46, 0x86, 0xd9, 0xf4, 0xc5, 0xe2, 0xf0, 0x54,
2617e265cbbSriastradh 	0xde, 0x41, 0xf6, 0xa1, 0xef, 0x1b, 0x0a, 0xea,
2627e265cbbSriastradh };
2637e265cbbSriastradh 
2647e265cbbSriastradh static const uint8_t selftest_bf_cbc_key[56] = {
2657e265cbbSriastradh 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2667e265cbbSriastradh 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2677e265cbbSriastradh 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2687e265cbbSriastradh 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
2697e265cbbSriastradh 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
2707e265cbbSriastradh 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
2717e265cbbSriastradh 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
2727e265cbbSriastradh };
2737e265cbbSriastradh 
2747e265cbbSriastradh static const uint8_t selftest_bf_cbc_ptxt[64] = {
2757e265cbbSriastradh 	0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
2767e265cbbSriastradh 	0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
2777e265cbbSriastradh 	0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
2787e265cbbSriastradh 	0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
2797e265cbbSriastradh 	0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
2807e265cbbSriastradh 	0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
2817e265cbbSriastradh 	0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
2827e265cbbSriastradh 	0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
2837e265cbbSriastradh };
2847e265cbbSriastradh 
2857e265cbbSriastradh static const uint8_t selftest_bf_cbc_ctxt[64] = {
2867e265cbbSriastradh 	0xec, 0xa2, 0xc0, 0x0e, 0xa9, 0x7f, 0x04, 0x1e,
2877e265cbbSriastradh 	0x2e, 0x4f, 0x64, 0x07, 0x67, 0x3e, 0xf4, 0x58,
2887e265cbbSriastradh 	0x61, 0x5f, 0xd3, 0x50, 0x5e, 0xd3, 0x4d, 0x34,
2897e265cbbSriastradh 	0xa0, 0x53, 0xbe, 0x47, 0x75, 0x69, 0x3b, 0x1f,
2907e265cbbSriastradh 	0x86, 0xf2, 0xae, 0x8b, 0xb7, 0x91, 0xda, 0xd4,
2917e265cbbSriastradh 	0x2b, 0xa5, 0x47, 0x9b, 0x7d, 0x13, 0x30, 0xdd,
2927e265cbbSriastradh 	0x7b, 0xad, 0x86, 0x57, 0x51, 0x11, 0x74, 0x42,
2937e265cbbSriastradh 	0xb8, 0xbf, 0x69, 0x17, 0x20, 0x0a, 0xf7, 0xda,
2947e265cbbSriastradh };
2957e265cbbSriastradh 
2965b0a15b1Sriastradh static const uint8_t selftest_aes_cbc_encblkno8_zero64[64];
2975b0a15b1Sriastradh static const uint8_t selftest_aes_cbc_encblkno8_ctxt[64] = {
2985b0a15b1Sriastradh 	0xa2, 0x06, 0x26, 0x26, 0xac, 0xdc, 0xe7, 0xcf,
2995b0a15b1Sriastradh 	0x47, 0x68, 0x24, 0x0e, 0xfa, 0x40, 0x44, 0x83,
3005b0a15b1Sriastradh 	0x07, 0xe1, 0xf4, 0x5d, 0x53, 0x47, 0xa0, 0xfe,
3015b0a15b1Sriastradh 	0xc0, 0x6e, 0x4e, 0xf8, 0x9d, 0x98, 0x63, 0xb8,
3025b0a15b1Sriastradh 	0x2c, 0x27, 0xfa, 0x3a, 0xd5, 0x40, 0xda, 0xdb,
3035b0a15b1Sriastradh 	0xe6, 0xc3, 0xe4, 0xfb, 0x85, 0x53, 0xfb, 0x78,
3045b0a15b1Sriastradh 	0x5d, 0xbd, 0x8f, 0x4c, 0x1a, 0x04, 0x9c, 0x88,
3055b0a15b1Sriastradh 	0x85, 0xec, 0x3c, 0x56, 0x46, 0x1a, 0x6e, 0xf5,
3065b0a15b1Sriastradh };
3075b0a15b1Sriastradh 
308b21f21dfSalnsn const struct selftest_params selftests[] = {
309b21f21dfSalnsn 	{
310b21f21dfSalnsn 		.alg = "aes-xts",
311b21f21dfSalnsn 		.blocksize = 16,
312b21f21dfSalnsn 		.secsize = 512,
313b21f21dfSalnsn 		.blkno = 1,
314b21f21dfSalnsn 		.keylen = 256,
315b21f21dfSalnsn 		.txtlen = sizeof(selftest_aes_xts_256_ptxt),
316b21f21dfSalnsn 		.key  = selftest_aes_xts_256_key,
317b21f21dfSalnsn 		.ptxt = selftest_aes_xts_256_ptxt,
318b21f21dfSalnsn 		.ctxt = selftest_aes_xts_256_ctxt
319b21f21dfSalnsn 	},
320b21f21dfSalnsn 	{
321b21f21dfSalnsn 		.alg = "aes-xts",
322b21f21dfSalnsn 		.blocksize = 16,
323b21f21dfSalnsn 		.secsize = 512,
324b21f21dfSalnsn 		.blkno = 0xffff,
325b21f21dfSalnsn 		.keylen = 512,
326b21f21dfSalnsn 		.txtlen = sizeof(selftest_aes_xts_512_ptxt),
327b21f21dfSalnsn 		.key  = selftest_aes_xts_512_key,
328b21f21dfSalnsn 		.ptxt = selftest_aes_xts_512_ptxt,
329b21f21dfSalnsn 		.ctxt = selftest_aes_xts_512_ctxt
3307e265cbbSriastradh 	},
3317e265cbbSriastradh 	{
3327e265cbbSriastradh 		.alg = "aes-cbc",
3337e265cbbSriastradh 		.blocksize = 16,
3347e265cbbSriastradh 		.secsize = 512,
3357e265cbbSriastradh 		.blkno = 1,
3367e265cbbSriastradh 		.keylen = 128,
3377e265cbbSriastradh 		.txtlen = sizeof(selftest_aes_cbc_128_ptxt),
3387e265cbbSriastradh 		.key  = selftest_aes_cbc_key,
3397e265cbbSriastradh 		.ptxt = selftest_aes_cbc_128_ptxt,
3407e265cbbSriastradh 		.ctxt = selftest_aes_cbc_128_ctxt,
3417e265cbbSriastradh 	},
3427e265cbbSriastradh 	{
3437e265cbbSriastradh 		.alg = "aes-cbc",
3447e265cbbSriastradh 		.blocksize = 16,
3457e265cbbSriastradh 		.secsize = 512,
3467e265cbbSriastradh 		.blkno = 0xffff,
3477e265cbbSriastradh 		.keylen = 256,
3487e265cbbSriastradh 		.txtlen = sizeof(selftest_aes_cbc_256_ptxt),
3497e265cbbSriastradh 		.key  = selftest_aes_cbc_key,
3507e265cbbSriastradh 		.ptxt = selftest_aes_cbc_256_ptxt,
3517e265cbbSriastradh 		.ctxt = selftest_aes_cbc_256_ctxt,
3527e265cbbSriastradh 	},
3537e265cbbSriastradh 	{
3547e265cbbSriastradh 		.alg = "3des-cbc",
3557e265cbbSriastradh 		.blocksize = 8,
3567e265cbbSriastradh 		.secsize = 512,
3577e265cbbSriastradh 		.blkno = 1,
3587e265cbbSriastradh 		.keylen = 192,	/* 168 + 3*8 parity bits */
3597e265cbbSriastradh 		.txtlen = sizeof(selftest_3des_cbc_ptxt),
3607e265cbbSriastradh 		.key  = selftest_3des_cbc_key,
3617e265cbbSriastradh 		.ptxt = selftest_3des_cbc_ptxt,
3627e265cbbSriastradh 		.ctxt = selftest_3des_cbc_ctxt,
3637e265cbbSriastradh 	},
3647e265cbbSriastradh 	{
3657e265cbbSriastradh 		.alg = "blowfish-cbc",
3667e265cbbSriastradh 		.blocksize = 8,
3677e265cbbSriastradh 		.secsize = 512,
3687e265cbbSriastradh 		.blkno = 1,
3697e265cbbSriastradh 		.keylen = 448,
3707e265cbbSriastradh 		.txtlen = sizeof(selftest_bf_cbc_ptxt),
3717e265cbbSriastradh 		.key  = selftest_bf_cbc_key,
3727e265cbbSriastradh 		.ptxt = selftest_bf_cbc_ptxt,
3737e265cbbSriastradh 		.ctxt = selftest_bf_cbc_ctxt,
3747e265cbbSriastradh 	},
3755b0a15b1Sriastradh 	{
3765b0a15b1Sriastradh 		.alg = "aes-cbc",
3775b0a15b1Sriastradh 		.encblkno8 = 1,
3785b0a15b1Sriastradh 		.blocksize = 16,
3795b0a15b1Sriastradh 		.secsize = 512,
3805b0a15b1Sriastradh 		.blkno = 0,
3815b0a15b1Sriastradh 		.keylen = 128,
3825b0a15b1Sriastradh 		.txtlen = sizeof(selftest_aes_cbc_encblkno8_zero64),
3835b0a15b1Sriastradh 		.key = selftest_aes_cbc_encblkno8_zero64,
3845b0a15b1Sriastradh 		.ptxt = selftest_aes_cbc_encblkno8_zero64,
3855b0a15b1Sriastradh 		.ctxt = selftest_aes_cbc_encblkno8_ctxt,
3865b0a15b1Sriastradh 	},
387b21f21dfSalnsn };
388b21f21dfSalnsn 
3891b379d7aSdyoung static int cgd_match(device_t, cfdata_t, void *);
3901b379d7aSdyoung static void cgd_attach(device_t, device_t, void *);
3911b379d7aSdyoung static int cgd_detach(device_t, int);
3921b379d7aSdyoung static struct cgd_softc	*cgd_spawn(int);
393afc6579bSmlelstv static struct cgd_worker *cgd_create_one_worker(void);
394afc6579bSmlelstv static void cgd_destroy_one_worker(struct cgd_worker *);
395afc6579bSmlelstv static struct cgd_worker *cgd_create_worker(void);
396afc6579bSmlelstv static void cgd_destroy_worker(struct cgd_worker *);
3971b379d7aSdyoung static int cgd_destroy(device_t);
3981b379d7aSdyoung 
3994366a007Selric /* Internal Functions */
4004366a007Selric 
40128e124faSmlelstv static int	cgd_diskstart(device_t, struct buf *);
402afc6579bSmlelstv static void	cgd_diskstart2(struct cgd_softc *, struct cgd_xfer *);
4034366a007Selric static void	cgdiodone(struct buf *);
404afc6579bSmlelstv static void	cgd_iodone2(struct cgd_softc *, struct cgd_xfer *);
405afc6579bSmlelstv static void	cgd_enqueue(struct cgd_softc *, struct cgd_xfer *);
406afc6579bSmlelstv static void	cgd_process(struct work *, void *);
407de8d1fd3Sriastradh static int	cgd_dumpblocks(device_t, void *, daddr_t, int);
4084366a007Selric 
40995e1ffb1Schristos static int	cgd_ioctl_set(struct cgd_softc *, void *, struct lwp *);
4101b379d7aSdyoung static int	cgd_ioctl_clr(struct cgd_softc *, struct lwp *);
4110f179f79Schristos static int	cgd_ioctl_get(dev_t, void *, struct lwp *);
4129b0c1757Sdrochner static int	cgdinit(struct cgd_softc *, const char *, struct vnode *,
41395e1ffb1Schristos 			struct lwp *);
414f7a9d62bSriastradh static void	cgd_cipher(struct cgd_softc *, void *, const void *,
4154366a007Selric 			   size_t, daddr_t, size_t, int);
4164366a007Selric 
41749fd8cb3Sriastradh static void	cgd_selftest(void);
41849fd8cb3Sriastradh 
419babb6cb1Smaxv static const struct dkdriver cgddkdriver = {
4205cb036f6Syamt         .d_minphys  = minphys,
4215f991650Smlelstv         .d_open = cgdopen,
4225f991650Smlelstv         .d_close = cgdclose,
4235f991650Smlelstv         .d_strategy = cgdstrategy,
4245f991650Smlelstv         .d_iosize = NULL,
42528e124faSmlelstv         .d_diskstart = cgd_diskstart,
426de8d1fd3Sriastradh         .d_dumpblocks = cgd_dumpblocks,
4275f991650Smlelstv         .d_lastclose = NULL
4285cb036f6Syamt };
4295cb036f6Syamt 
4301b379d7aSdyoung CFATTACH_DECL3_NEW(cgd, sizeof(struct cgd_softc),
4311b379d7aSdyoung     cgd_match, cgd_attach, cgd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
4321b379d7aSdyoung 
4334366a007Selric /* DIAGNOSTIC and DEBUG definitions */
4344366a007Selric 
4354366a007Selric #if defined(CGDDEBUG) && !defined(DEBUG)
4364366a007Selric #define DEBUG
4374366a007Selric #endif
4384366a007Selric 
4394366a007Selric #ifdef DEBUG
4404366a007Selric int cgddebug = 0;
4414366a007Selric 
4424366a007Selric #define CGDB_FOLLOW	0x1
4434366a007Selric #define CGDB_IO	0x2
4444366a007Selric #define CGDB_CRYPTO	0x4
4454366a007Selric 
4464366a007Selric #define IFDEBUG(x,y)		if (cgddebug & (x)) y
4474366a007Selric #define DPRINTF(x,y)		IFDEBUG(x, printf y)
4484366a007Selric #define DPRINTF_FOLLOW(y)	DPRINTF(CGDB_FOLLOW, y)
4494366a007Selric 
45031924c84Sdrochner static void	hexprint(const char *, void *, int);
4514366a007Selric 
4524366a007Selric #else
4534366a007Selric #define IFDEBUG(x,y)
4544366a007Selric #define DPRINTF(x,y)
4554366a007Selric #define DPRINTF_FOLLOW(y)
4564366a007Selric #endif
4574366a007Selric 
4584366a007Selric /* Global variables */
4594366a007Selric 
460afc6579bSmlelstv static kmutex_t cgd_spawning_mtx;
461afc6579bSmlelstv static kcondvar_t cgd_spawning_cv;
462afc6579bSmlelstv static bool cgd_spawning;
463afc6579bSmlelstv static struct cgd_worker *cgd_worker;
464afc6579bSmlelstv static u_int cgd_refcnt;	/* number of users of cgd_worker */
465afc6579bSmlelstv 
4664366a007Selric /* Utility Functions */
4674366a007Selric 
4684366a007Selric #define CGDUNIT(x)		DISKUNIT(x)
4694366a007Selric 
4701b379d7aSdyoung /* The code */
4711b379d7aSdyoung 
472afc6579bSmlelstv static int
cgd_lock(bool intr)473afc6579bSmlelstv cgd_lock(bool intr)
474afc6579bSmlelstv {
475afc6579bSmlelstv 	int error = 0;
476afc6579bSmlelstv 
477afc6579bSmlelstv 	mutex_enter(&cgd_spawning_mtx);
478afc6579bSmlelstv 	while (cgd_spawning) {
479afc6579bSmlelstv 		if (intr)
480afc6579bSmlelstv 			error = cv_wait_sig(&cgd_spawning_cv, &cgd_spawning_mtx);
481afc6579bSmlelstv 		else
482afc6579bSmlelstv 			cv_wait(&cgd_spawning_cv, &cgd_spawning_mtx);
483afc6579bSmlelstv 	}
484afc6579bSmlelstv 	if (error == 0)
485afc6579bSmlelstv 		cgd_spawning = true;
486afc6579bSmlelstv 	mutex_exit(&cgd_spawning_mtx);
487afc6579bSmlelstv 	return error;
488afc6579bSmlelstv }
489afc6579bSmlelstv 
490afc6579bSmlelstv static void
cgd_unlock(void)491afc6579bSmlelstv cgd_unlock(void)
492afc6579bSmlelstv {
493afc6579bSmlelstv 	mutex_enter(&cgd_spawning_mtx);
494afc6579bSmlelstv 	cgd_spawning = false;
495afc6579bSmlelstv 	cv_broadcast(&cgd_spawning_cv);
496afc6579bSmlelstv 	mutex_exit(&cgd_spawning_mtx);
497afc6579bSmlelstv }
498afc6579bSmlelstv 
4994366a007Selric static struct cgd_softc *
getcgd_softc(dev_t dev)5004366a007Selric getcgd_softc(dev_t dev)
5014366a007Selric {
502afc6579bSmlelstv 	return device_lookup_private(&cgd_cd, CGDUNIT(dev));
5034366a007Selric }
5044366a007Selric 
5051b379d7aSdyoung static int
cgd_match(device_t self,cfdata_t cfdata,void * aux)5061b379d7aSdyoung cgd_match(device_t self, cfdata_t cfdata, void *aux)
5071b379d7aSdyoung {
5081b379d7aSdyoung 
5091b379d7aSdyoung 	return 1;
5101b379d7aSdyoung }
5114366a007Selric 
5124366a007Selric static void
cgd_attach(device_t parent,device_t self,void * aux)5131b379d7aSdyoung cgd_attach(device_t parent, device_t self, void *aux)
5144366a007Selric {
5151b379d7aSdyoung 	struct cgd_softc *sc = device_private(self);
5164366a007Selric 
517b7fe3a93Sskrll 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO);
518afc6579bSmlelstv 	cv_init(&sc->sc_cv, "cgdcv");
5195f991650Smlelstv 	dk_init(&sc->sc_dksc, self, DKTYPE_CGD);
5201b379d7aSdyoung 	disk_init(&sc->sc_dksc.sc_dkdev, sc->sc_dksc.sc_xname, &cgddkdriver);
521b6f836a2Sjoerg 
522b6f836a2Sjoerg 	if (!pmf_device_register(self, NULL, NULL))
5238bc54e5bSmsaitoh 		aprint_error_dev(self,
5248bc54e5bSmsaitoh 		    "unable to register power management hooks\n");
5251b379d7aSdyoung }
5261b379d7aSdyoung 
5271b379d7aSdyoung 
5281b379d7aSdyoung static int
cgd_detach(device_t self,int flags)5291b379d7aSdyoung cgd_detach(device_t self, int flags)
5301b379d7aSdyoung {
531c95d6a20Sdyoung 	int ret;
5321b379d7aSdyoung 	struct cgd_softc *sc = device_private(self);
533c95d6a20Sdyoung 	struct dk_softc *dksc = &sc->sc_dksc;
5341b379d7aSdyoung 
5354a85b256Sriastradh 	if (DK_BUSY(dksc, 0))
536c95d6a20Sdyoung 		return EBUSY;
5371b379d7aSdyoung 
5385f991650Smlelstv 	if (DK_ATTACHED(dksc) &&
539c95d6a20Sdyoung 	    (ret = cgd_ioctl_clr(sc, curlwp)) != 0)
5401b379d7aSdyoung 		return ret;
541c95d6a20Sdyoung 
542c95d6a20Sdyoung 	disk_destroy(&dksc->sc_dkdev);
543afc6579bSmlelstv 	cv_destroy(&sc->sc_cv);
5441b2d99ceSchristos 	mutex_destroy(&sc->sc_lock);
545c95d6a20Sdyoung 
546c95d6a20Sdyoung 	return 0;
5474366a007Selric }
5484366a007Selric 
5494366a007Selric void
cgdattach(int num)5504366a007Selric cgdattach(int num)
5514366a007Selric {
552afc6579bSmlelstv #ifndef _MODULE
5531b379d7aSdyoung 	int error;
5544366a007Selric 
555afc6579bSmlelstv 	mutex_init(&cgd_spawning_mtx, MUTEX_DEFAULT, IPL_NONE);
556afc6579bSmlelstv 	cv_init(&cgd_spawning_cv, "cgspwn");
557afc6579bSmlelstv 
5581b379d7aSdyoung 	error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
5591b379d7aSdyoung 	if (error != 0)
5601b379d7aSdyoung 		aprint_error("%s: unable to register cfattach\n",
5611b379d7aSdyoung 		    cgd_cd.cd_name);
562afc6579bSmlelstv #endif
56349fd8cb3Sriastradh 
56449fd8cb3Sriastradh 	cgd_selftest();
5654366a007Selric }
5664366a007Selric 
5671b379d7aSdyoung static struct cgd_softc *
cgd_spawn(int unit)5681b379d7aSdyoung cgd_spawn(int unit)
5691b379d7aSdyoung {
5701b379d7aSdyoung 	cfdata_t cf;
571afc6579bSmlelstv 	struct cgd_worker *cw;
572afc6579bSmlelstv 	struct cgd_softc *sc;
5731b379d7aSdyoung 
574afc6579bSmlelstv 	cf = kmem_alloc(sizeof(*cf), KM_SLEEP);
5751b379d7aSdyoung 	cf->cf_name = cgd_cd.cd_name;
5761b379d7aSdyoung 	cf->cf_atname = cgd_cd.cd_name;
5771b379d7aSdyoung 	cf->cf_unit = unit;
5781b379d7aSdyoung 	cf->cf_fstate = FSTATE_STAR;
5791b379d7aSdyoung 
580afc6579bSmlelstv 	cw = cgd_create_one_worker();
581afc6579bSmlelstv 	if (cw == NULL) {
582afc6579bSmlelstv 		kmem_free(cf, sizeof(*cf));
583afc6579bSmlelstv 		return NULL;
584afc6579bSmlelstv 	}
585afc6579bSmlelstv 
586afc6579bSmlelstv 	sc = device_private(config_attach_pseudo(cf));
587afc6579bSmlelstv 	if (sc == NULL) {
588afc6579bSmlelstv 		cgd_destroy_one_worker(cw);
589afc6579bSmlelstv 		return NULL;
590afc6579bSmlelstv 	}
591afc6579bSmlelstv 
592afc6579bSmlelstv 	sc->sc_worker = cw;
593afc6579bSmlelstv 
594afc6579bSmlelstv 	return sc;
5954366a007Selric }
5964366a007Selric 
5971b379d7aSdyoung static int
cgd_destroy(device_t dev)5981b379d7aSdyoung cgd_destroy(device_t dev)
5991b379d7aSdyoung {
600afc6579bSmlelstv 	struct cgd_softc *sc = device_private(dev);
601afc6579bSmlelstv 	struct cgd_worker *cw = sc->sc_worker;
6021b379d7aSdyoung 	cfdata_t cf;
603afc6579bSmlelstv 	int error;
6041b379d7aSdyoung 
6051b379d7aSdyoung 	cf = device_cfdata(dev);
6061b379d7aSdyoung 	error = config_detach(dev, DETACH_QUIET);
6071b379d7aSdyoung 	if (error)
6081b379d7aSdyoung 		return error;
609afc6579bSmlelstv 
610afc6579bSmlelstv 	cgd_destroy_one_worker(cw);
611afc6579bSmlelstv 
612afc6579bSmlelstv 	kmem_free(cf, sizeof(*cf));
6131b379d7aSdyoung 	return 0;
6144366a007Selric }
6154366a007Selric 
616afc6579bSmlelstv static void
cgd_busy(struct cgd_softc * sc)617afc6579bSmlelstv cgd_busy(struct cgd_softc *sc)
618afc6579bSmlelstv {
619afc6579bSmlelstv 
620afc6579bSmlelstv 	mutex_enter(&sc->sc_lock);
621afc6579bSmlelstv 	while (sc->sc_busy)
622afc6579bSmlelstv 		cv_wait(&sc->sc_cv, &sc->sc_lock);
623afc6579bSmlelstv 	sc->sc_busy = true;
624afc6579bSmlelstv 	mutex_exit(&sc->sc_lock);
625afc6579bSmlelstv }
626afc6579bSmlelstv 
627afc6579bSmlelstv static void
cgd_unbusy(struct cgd_softc * sc)628afc6579bSmlelstv cgd_unbusy(struct cgd_softc *sc)
629afc6579bSmlelstv {
630afc6579bSmlelstv 
631afc6579bSmlelstv 	mutex_enter(&sc->sc_lock);
632afc6579bSmlelstv 	sc->sc_busy = false;
633afc6579bSmlelstv 	cv_broadcast(&sc->sc_cv);
634afc6579bSmlelstv 	mutex_exit(&sc->sc_lock);
635afc6579bSmlelstv }
636afc6579bSmlelstv 
637afc6579bSmlelstv static struct cgd_worker *
cgd_create_one_worker(void)638afc6579bSmlelstv cgd_create_one_worker(void)
639afc6579bSmlelstv {
640afc6579bSmlelstv 	KASSERT(cgd_spawning);
641afc6579bSmlelstv 
642afc6579bSmlelstv 	if (cgd_refcnt++ == 0) {
643afc6579bSmlelstv 		KASSERT(cgd_worker == NULL);
644afc6579bSmlelstv 		cgd_worker = cgd_create_worker();
645afc6579bSmlelstv 	}
646afc6579bSmlelstv 
647afc6579bSmlelstv 	KASSERT(cgd_worker != NULL);
648afc6579bSmlelstv 	return cgd_worker;
649afc6579bSmlelstv }
650afc6579bSmlelstv 
651afc6579bSmlelstv static void
cgd_destroy_one_worker(struct cgd_worker * cw)652afc6579bSmlelstv cgd_destroy_one_worker(struct cgd_worker *cw)
653afc6579bSmlelstv {
654afc6579bSmlelstv 	KASSERT(cgd_spawning);
655afc6579bSmlelstv 	KASSERT(cw == cgd_worker);
656afc6579bSmlelstv 
657afc6579bSmlelstv 	if (--cgd_refcnt == 0) {
658afc6579bSmlelstv 		cgd_destroy_worker(cgd_worker);
659afc6579bSmlelstv 		cgd_worker = NULL;
660afc6579bSmlelstv 	}
661afc6579bSmlelstv }
662afc6579bSmlelstv 
663afc6579bSmlelstv static struct cgd_worker *
cgd_create_worker(void)664afc6579bSmlelstv cgd_create_worker(void)
665afc6579bSmlelstv {
666afc6579bSmlelstv 	struct cgd_worker *cw;
667afc6579bSmlelstv 	struct workqueue *wq;
668afc6579bSmlelstv 	struct pool *cp;
669afc6579bSmlelstv 	int error;
670afc6579bSmlelstv 
671afc6579bSmlelstv 	cw = kmem_alloc(sizeof(struct cgd_worker), KM_SLEEP);
672afc6579bSmlelstv 	cp = kmem_alloc(sizeof(struct pool), KM_SLEEP);
673afc6579bSmlelstv 
674afc6579bSmlelstv 	error = workqueue_create(&wq, "cgd", cgd_process, NULL,
675c8aa63b5Sriastradh 	    PRI_BIO, IPL_BIO, WQ_FPU|WQ_MPSAFE|WQ_PERCPU);
676afc6579bSmlelstv 	if (error) {
677afc6579bSmlelstv 		kmem_free(cp, sizeof(struct pool));
678afc6579bSmlelstv 		kmem_free(cw, sizeof(struct cgd_worker));
679afc6579bSmlelstv 		return NULL;
680afc6579bSmlelstv 	}
681afc6579bSmlelstv 
682afc6579bSmlelstv 	cw->cw_cpool = cp;
683afc6579bSmlelstv 	cw->cw_wq = wq;
684afc6579bSmlelstv 	pool_init(cw->cw_cpool, sizeof(struct cgd_xfer), 0,
685afc6579bSmlelstv 	    0, 0, "cgdcpl", NULL, IPL_BIO);
686afc6579bSmlelstv 	mutex_init(&cw->cw_lock, MUTEX_DEFAULT, IPL_BIO);
687afc6579bSmlelstv 
688afc6579bSmlelstv 	return cw;
689afc6579bSmlelstv }
690afc6579bSmlelstv 
691afc6579bSmlelstv static void
cgd_destroy_worker(struct cgd_worker * cw)692afc6579bSmlelstv cgd_destroy_worker(struct cgd_worker *cw)
693afc6579bSmlelstv {
6946c1d7ecaSriastradh 
6956c1d7ecaSriastradh 	/*
6966c1d7ecaSriastradh 	 * Wait for all worker threads to complete before destroying
6976c1d7ecaSriastradh 	 * the rest of the cgd_worker.
6986c1d7ecaSriastradh 	 */
6996c1d7ecaSriastradh 	if (cw->cw_wq)
7006c1d7ecaSriastradh 		workqueue_destroy(cw->cw_wq);
7016c1d7ecaSriastradh 
702afc6579bSmlelstv 	mutex_destroy(&cw->cw_lock);
703afc6579bSmlelstv 
704afc6579bSmlelstv 	if (cw->cw_cpool) {
705afc6579bSmlelstv 		pool_destroy(cw->cw_cpool);
706afc6579bSmlelstv 		kmem_free(cw->cw_cpool, sizeof(struct pool));
707afc6579bSmlelstv 	}
708afc6579bSmlelstv 
709afc6579bSmlelstv 	kmem_free(cw, sizeof(struct cgd_worker));
710afc6579bSmlelstv }
711afc6579bSmlelstv 
712a1bb10efSthorpej static int
cgdopen(dev_t dev,int flags,int fmt,struct lwp * l)71395e1ffb1Schristos cgdopen(dev_t dev, int flags, int fmt, struct lwp *l)
7144366a007Selric {
715afc6579bSmlelstv 	struct	cgd_softc *sc;
716afc6579bSmlelstv 	int error;
7174366a007Selric 
71808ebead9Scegger 	DPRINTF_FOLLOW(("cgdopen(0x%"PRIx64", %d)\n", dev, flags));
719afc6579bSmlelstv 
720afc6579bSmlelstv 	error = cgd_lock(true);
721afc6579bSmlelstv 	if (error)
722afc6579bSmlelstv 		return error;
723afc6579bSmlelstv 	sc = getcgd_softc(dev);
724afc6579bSmlelstv 	if (sc == NULL)
725afc6579bSmlelstv 		sc = cgd_spawn(CGDUNIT(dev));
726afc6579bSmlelstv 	cgd_unlock();
727afc6579bSmlelstv 	if (sc == NULL)
728afc6579bSmlelstv 		return ENXIO;
729afc6579bSmlelstv 
730afc6579bSmlelstv 	return dk_open(&sc->sc_dksc, dev, flags, fmt, l);
7314366a007Selric }
7324366a007Selric 
733a1bb10efSthorpej static int
cgdclose(dev_t dev,int flags,int fmt,struct lwp * l)73495e1ffb1Schristos cgdclose(dev_t dev, int flags, int fmt, struct lwp *l)
7354366a007Selric {
736afc6579bSmlelstv 	struct	cgd_softc *sc;
7371b379d7aSdyoung 	struct	dk_softc *dksc;
738afc6579bSmlelstv 	int error;
7394366a007Selric 
74008ebead9Scegger 	DPRINTF_FOLLOW(("cgdclose(0x%"PRIx64", %d)\n", dev, flags));
741afc6579bSmlelstv 
742afc6579bSmlelstv 	error = cgd_lock(false);
743afc6579bSmlelstv 	if (error)
7441b379d7aSdyoung 		return error;
745afc6579bSmlelstv 	sc = getcgd_softc(dev);
746afc6579bSmlelstv 	if (sc == NULL) {
747afc6579bSmlelstv 		error = ENXIO;
748afc6579bSmlelstv 		goto done;
749afc6579bSmlelstv 	}
750afc6579bSmlelstv 
751afc6579bSmlelstv 	dksc = &sc->sc_dksc;
752afc6579bSmlelstv 	if ((error =  dk_close(dksc, dev, flags, fmt, l)) != 0)
753afc6579bSmlelstv 		goto done;
7541b379d7aSdyoung 
7555f991650Smlelstv 	if (!DK_ATTACHED(dksc)) {
756afc6579bSmlelstv 		if ((error = cgd_destroy(sc->sc_dksc.sc_dev)) != 0) {
757afc6579bSmlelstv 			device_printf(dksc->sc_dev,
7581b379d7aSdyoung 			    "unable to detach instance\n");
759afc6579bSmlelstv 			goto done;
760afc6579bSmlelstv 		}
761afc6579bSmlelstv 	}
762afc6579bSmlelstv 
763afc6579bSmlelstv done:
764afc6579bSmlelstv 	cgd_unlock();
765afc6579bSmlelstv 
7661b379d7aSdyoung 	return error;
7671b379d7aSdyoung }
7684366a007Selric 
769a1bb10efSthorpej static void
cgdstrategy(struct buf * bp)7704366a007Selric cgdstrategy(struct buf *bp)
7714366a007Selric {
772afc6579bSmlelstv 	struct	cgd_softc *sc = getcgd_softc(bp->b_dev);
7734366a007Selric 
7744366a007Selric 	DPRINTF_FOLLOW(("cgdstrategy(%p): b_bcount = %ld\n", bp,
7754366a007Selric 	    (long)bp->b_bcount));
7761e0dbea9Sriastradh 
777f7dd6a08Smlelstv 	/*
778f7dd6a08Smlelstv 	 * Reject unaligned writes.
779f7dd6a08Smlelstv 	 */
780f7dd6a08Smlelstv 	if (((uintptr_t)bp->b_data & 3) != 0) {
781f7dd6a08Smlelstv 		bp->b_error = EINVAL;
782f7dd6a08Smlelstv 		goto bail;
783f7dd6a08Smlelstv 	}
784f7dd6a08Smlelstv 
785afc6579bSmlelstv 	dk_strategy(&sc->sc_dksc, bp);
7864366a007Selric 	return;
787f7dd6a08Smlelstv 
788f7dd6a08Smlelstv bail:
789f7dd6a08Smlelstv 	bp->b_resid = bp->b_bcount;
790f7dd6a08Smlelstv 	biodone(bp);
791f7dd6a08Smlelstv 	return;
7924366a007Selric }
7934366a007Selric 
794a1bb10efSthorpej static int
cgdsize(dev_t dev)7954366a007Selric cgdsize(dev_t dev)
7964366a007Selric {
797afc6579bSmlelstv 	struct cgd_softc *sc = getcgd_softc(dev);
7984366a007Selric 
79908ebead9Scegger 	DPRINTF_FOLLOW(("cgdsize(0x%"PRIx64")\n", dev));
800afc6579bSmlelstv 	if (!sc)
8014366a007Selric 		return -1;
802afc6579bSmlelstv 	return dk_size(&sc->sc_dksc, dev);
8034366a007Selric }
8044366a007Selric 
805befeae89Selric /*
806befeae89Selric  * cgd_{get,put}data are functions that deal with getting a buffer
807afc6579bSmlelstv  * for the new encrypted data.
808afc6579bSmlelstv  * We can no longer have a buffer per device, we need a buffer per
809afc6579bSmlelstv  * work queue...
810befeae89Selric  */
811befeae89Selric 
812befeae89Selric static void *
cgd_getdata(struct cgd_softc * sc,unsigned long size)813afc6579bSmlelstv cgd_getdata(struct cgd_softc *sc, unsigned long size)
814befeae89Selric {
81553524e44Schristos 	void *data = NULL;
816befeae89Selric 
817afc6579bSmlelstv 	mutex_enter(&sc->sc_lock);
818afc6579bSmlelstv 	if (!sc->sc_data_used) {
819afc6579bSmlelstv 		sc->sc_data_used = true;
820afc6579bSmlelstv 		data = sc->sc_data;
821befeae89Selric 	}
822afc6579bSmlelstv 	mutex_exit(&sc->sc_lock);
823befeae89Selric 
824befeae89Selric 	if (data)
825befeae89Selric 		return data;
826befeae89Selric 
827067e9296Stnn 	return kmem_intr_alloc(size, KM_NOSLEEP);
828befeae89Selric }
829befeae89Selric 
8304366a007Selric static void
cgd_putdata(struct cgd_softc * sc,void * data,unsigned long size)831067e9296Stnn cgd_putdata(struct cgd_softc *sc, void *data, unsigned long size)
832befeae89Selric {
833befeae89Selric 
834afc6579bSmlelstv 	if (data == sc->sc_data) {
835afc6579bSmlelstv 		mutex_enter(&sc->sc_lock);
836afc6579bSmlelstv 		sc->sc_data_used = false;
837afc6579bSmlelstv 		mutex_exit(&sc->sc_lock);
838afc6579bSmlelstv 	} else
839067e9296Stnn 		kmem_intr_free(data, size);
840befeae89Selric }
841befeae89Selric 
84228e124faSmlelstv static int
cgd_diskstart(device_t dev,struct buf * bp)84328e124faSmlelstv cgd_diskstart(device_t dev, struct buf *bp)
8444366a007Selric {
845afc6579bSmlelstv 	struct	cgd_softc *sc = device_private(dev);
846afc6579bSmlelstv 	struct	cgd_worker *cw = sc->sc_worker;
847afc6579bSmlelstv 	struct	dk_softc *dksc = &sc->sc_dksc;
8489c6a5e26Smlelstv 	struct	disk_geom *dg = &dksc->sc_dkdev.dk_geom;
849afc6579bSmlelstv 	struct	cgd_xfer *cx;
85028e124faSmlelstv 	struct	buf *nbp;
85153524e44Schristos 	void *	newaddr;
8524366a007Selric 	daddr_t	bn;
8534366a007Selric 
85428e124faSmlelstv 	DPRINTF_FOLLOW(("cgd_diskstart(%p, %p)\n", dksc, bp));
8554366a007Selric 
856464cf44fSyamt 	bn = bp->b_rawblkno;
8574366a007Selric 
8584366a007Selric 	/*
859befeae89Selric 	 * We attempt to allocate all of our resources up front, so that
860befeae89Selric 	 * we can fail quickly if they are unavailable.
861befeae89Selric 	 */
862afc6579bSmlelstv 	nbp = getiobuf(sc->sc_tvn, false);
86328e124faSmlelstv 	if (nbp == NULL)
86428e124faSmlelstv 		return EAGAIN;
865befeae89Selric 
866afc6579bSmlelstv 	cx = pool_get(cw->cw_cpool, PR_NOWAIT);
867afc6579bSmlelstv 	if (cx == NULL) {
868afc6579bSmlelstv 		putiobuf(nbp);
869afc6579bSmlelstv 		return EAGAIN;
870afc6579bSmlelstv 	}
871afc6579bSmlelstv 
872afc6579bSmlelstv 	cx->cx_sc = sc;
873afc6579bSmlelstv 	cx->cx_obp = bp;
874afc6579bSmlelstv 	cx->cx_nbp = nbp;
875afc6579bSmlelstv 	cx->cx_srcv = cx->cx_dstv = bp->b_data;
876afc6579bSmlelstv 	cx->cx_blkno = bn;
877afc6579bSmlelstv 	cx->cx_secsize = dg->dg_secsize;
878afc6579bSmlelstv 
879befeae89Selric 	/*
8804366a007Selric 	 * If we are writing, then we need to encrypt the outgoing
8812745b95eSbouyer 	 * block into a new block of memory.
8824366a007Selric 	 */
8834366a007Selric 	if ((bp->b_flags & B_READ) == 0) {
884afc6579bSmlelstv 		newaddr = cgd_getdata(sc, bp->b_bcount);
885befeae89Selric 		if (!newaddr) {
886afc6579bSmlelstv 			pool_put(cw->cw_cpool, cx);
887690d424fSyamt 			putiobuf(nbp);
88828e124faSmlelstv 			return EAGAIN;
889befeae89Selric 		}
890afc6579bSmlelstv 
891afc6579bSmlelstv 		cx->cx_dstv = newaddr;
892afc6579bSmlelstv 		cx->cx_len = bp->b_bcount;
893afc6579bSmlelstv 		cx->cx_dir = CGD_CIPHER_ENCRYPT;
894afc6579bSmlelstv 
895afc6579bSmlelstv 		cgd_enqueue(sc, cx);
896afc6579bSmlelstv 		return 0;
8974366a007Selric 	}
89828e124faSmlelstv 
899afc6579bSmlelstv 	cgd_diskstart2(sc, cx);
900afc6579bSmlelstv 	return 0;
901afc6579bSmlelstv }
902afc6579bSmlelstv 
903afc6579bSmlelstv static void
cgd_diskstart2(struct cgd_softc * sc,struct cgd_xfer * cx)904afc6579bSmlelstv cgd_diskstart2(struct cgd_softc *sc, struct cgd_xfer *cx)
905afc6579bSmlelstv {
906afc6579bSmlelstv 	struct	vnode *vp;
907afc6579bSmlelstv 	struct	buf *bp;
908afc6579bSmlelstv 	struct	buf *nbp;
909afc6579bSmlelstv 
910afc6579bSmlelstv 	bp = cx->cx_obp;
911afc6579bSmlelstv 	nbp = cx->cx_nbp;
912afc6579bSmlelstv 
913afc6579bSmlelstv 	nbp->b_data = cx->cx_dstv;
9144a780c9aSad 	nbp->b_flags = bp->b_flags;
9154a780c9aSad 	nbp->b_oflags = bp->b_oflags;
9164a780c9aSad 	nbp->b_cflags = bp->b_cflags;
917092bb864Sdbj 	nbp->b_iodone = cgdiodone;
918092bb864Sdbj 	nbp->b_proc = bp->b_proc;
919afc6579bSmlelstv 	nbp->b_blkno = btodb(cx->cx_blkno * cx->cx_secsize);
920092bb864Sdbj 	nbp->b_bcount = bp->b_bcount;
921afc6579bSmlelstv 	nbp->b_private = cx;
9224366a007Selric 
923092bb864Sdbj 	BIO_COPYPRIO(nbp, bp);
9244366a007Selric 
925092bb864Sdbj 	if ((nbp->b_flags & B_READ) == 0) {
9264a780c9aSad 		vp = nbp->b_vp;
927e225b7bdSrmind 		mutex_enter(vp->v_interlock);
9284a780c9aSad 		vp->v_numoutput++;
929e225b7bdSrmind 		mutex_exit(vp->v_interlock);
930092bb864Sdbj 	}
931afc6579bSmlelstv 	VOP_STRATEGY(sc->sc_tvn, nbp);
9324366a007Selric }
9334366a007Selric 
934a1bb10efSthorpej static void
cgdiodone(struct buf * nbp)935092bb864Sdbj cgdiodone(struct buf *nbp)
9364366a007Selric {
937afc6579bSmlelstv 	struct	cgd_xfer *cx = nbp->b_private;
938afc6579bSmlelstv 	struct	buf *obp = cx->cx_obp;
939afc6579bSmlelstv 	struct	cgd_softc *sc = getcgd_softc(obp->b_dev);
940afc6579bSmlelstv 	struct	dk_softc *dksc = &sc->sc_dksc;
9419c6a5e26Smlelstv 	struct	disk_geom *dg = &dksc->sc_dkdev.dk_geom;
9429c6a5e26Smlelstv 	daddr_t	bn;
9434366a007Selric 
944afc6579bSmlelstv 	KDASSERT(sc);
945092bb864Sdbj 
946092bb864Sdbj 	DPRINTF_FOLLOW(("cgdiodone(%p)\n", nbp));
9474a85dda9Syamt 	DPRINTF(CGDB_IO, ("cgdiodone: bp %p bcount %d resid %d\n",
9484366a007Selric 	    obp, obp->b_bcount, obp->b_resid));
9498bc54e5bSmsaitoh 	DPRINTF(CGDB_IO, (" dev 0x%"PRIx64", nbp %p bn %" PRId64
9508bc54e5bSmsaitoh 	    " addr %p bcnt %d\n", nbp->b_dev, nbp, nbp->b_blkno, nbp->b_data,
951092bb864Sdbj 		nbp->b_bcount));
952eb171eaaSad 	if (nbp->b_error != 0) {
953eb171eaaSad 		obp->b_error = nbp->b_error;
95418975112Schristos 		DPRINTF(CGDB_IO, ("%s: error %d\n", dksc->sc_xname,
95518975112Schristos 		    obp->b_error));
9564366a007Selric 	}
9574366a007Selric 
958befeae89Selric 	/* Perform the decryption if we are reading.
9594366a007Selric 	 *
9604366a007Selric 	 * Note: use the blocknumber from nbp, since it is what
9614366a007Selric 	 *       we used to encrypt the blocks.
9624366a007Selric 	 */
9634366a007Selric 
9649c6a5e26Smlelstv 	if (nbp->b_flags & B_READ) {
9659c6a5e26Smlelstv 		bn = dbtob(nbp->b_blkno) / dg->dg_secsize;
966afc6579bSmlelstv 
967afc6579bSmlelstv 		cx->cx_obp     = obp;
968afc6579bSmlelstv 		cx->cx_nbp     = nbp;
969afc6579bSmlelstv 		cx->cx_dstv    = obp->b_data;
970afc6579bSmlelstv 		cx->cx_srcv    = obp->b_data;
971afc6579bSmlelstv 		cx->cx_len     = obp->b_bcount;
972afc6579bSmlelstv 		cx->cx_blkno   = bn;
973afc6579bSmlelstv 		cx->cx_secsize = dg->dg_secsize;
974afc6579bSmlelstv 		cx->cx_dir     = CGD_CIPHER_DECRYPT;
975afc6579bSmlelstv 
976afc6579bSmlelstv 		cgd_enqueue(sc, cx);
977afc6579bSmlelstv 		return;
9789c6a5e26Smlelstv 	}
9794366a007Selric 
980afc6579bSmlelstv 	cgd_iodone2(sc, cx);
981afc6579bSmlelstv }
982afc6579bSmlelstv 
983afc6579bSmlelstv static void
cgd_iodone2(struct cgd_softc * sc,struct cgd_xfer * cx)984afc6579bSmlelstv cgd_iodone2(struct cgd_softc *sc, struct cgd_xfer *cx)
985afc6579bSmlelstv {
986afc6579bSmlelstv 	struct cgd_worker *cw = sc->sc_worker;
987afc6579bSmlelstv 	struct buf *obp = cx->cx_obp;
988afc6579bSmlelstv 	struct buf *nbp = cx->cx_nbp;
989afc6579bSmlelstv 	struct dk_softc *dksc = &sc->sc_dksc;
990afc6579bSmlelstv 
991afc6579bSmlelstv 	pool_put(cw->cw_cpool, cx);
992afc6579bSmlelstv 
993befeae89Selric 	/* If we allocated memory, free it now... */
9944366a007Selric 	if (nbp->b_data != obp->b_data)
995067e9296Stnn 		cgd_putdata(sc, nbp->b_data, nbp->b_bcount);
9964366a007Selric 
997690d424fSyamt 	putiobuf(nbp);
9984366a007Selric 
999155f12a5Smlelstv 	/* Request is complete for whatever reason */
1000155f12a5Smlelstv 	obp->b_resid = 0;
1001155f12a5Smlelstv 	if (obp->b_error != 0)
1002155f12a5Smlelstv 		obp->b_resid = obp->b_bcount;
1003155f12a5Smlelstv 
100428e124faSmlelstv 	dk_done(dksc, obp);
100520902f79Smlelstv 	dk_start(dksc, NULL);
10064366a007Selric }
10074366a007Selric 
1008de8d1fd3Sriastradh static int
cgd_dumpblocks(device_t dev,void * va,daddr_t blkno,int nblk)1009de8d1fd3Sriastradh cgd_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk)
1010de8d1fd3Sriastradh {
1011de8d1fd3Sriastradh 	struct cgd_softc *sc = device_private(dev);
1012de8d1fd3Sriastradh 	struct dk_softc *dksc = &sc->sc_dksc;
1013de8d1fd3Sriastradh 	struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
1014de8d1fd3Sriastradh 	size_t nbytes, blksize;
1015de8d1fd3Sriastradh 	void *buf;
1016de8d1fd3Sriastradh 	int error;
1017de8d1fd3Sriastradh 
1018de8d1fd3Sriastradh 	/*
1019de8d1fd3Sriastradh 	 * dk_dump gives us units of disklabel sectors.  Everything
1020de8d1fd3Sriastradh 	 * else in cgd uses units of diskgeom sectors.  These had
1021de8d1fd3Sriastradh 	 * better agree; otherwise we need to figure out how to convert
1022de8d1fd3Sriastradh 	 * between them.
1023de8d1fd3Sriastradh 	 */
1024de8d1fd3Sriastradh 	KASSERTMSG((dg->dg_secsize == dksc->sc_dkdev.dk_label->d_secsize),
1025de8d1fd3Sriastradh 	    "diskgeom secsize %"PRIu32" != disklabel secsize %"PRIu32,
1026de8d1fd3Sriastradh 	    dg->dg_secsize, dksc->sc_dkdev.dk_label->d_secsize);
1027de8d1fd3Sriastradh 	blksize = dg->dg_secsize;
1028de8d1fd3Sriastradh 
1029de8d1fd3Sriastradh 	/*
1030de8d1fd3Sriastradh 	 * Compute the number of bytes in this request, which dk_dump
1031de8d1fd3Sriastradh 	 * has `helpfully' converted to a number of blocks for us.
1032de8d1fd3Sriastradh 	 */
1033de8d1fd3Sriastradh 	nbytes = nblk*blksize;
1034de8d1fd3Sriastradh 
1035de8d1fd3Sriastradh 	/* Try to acquire a buffer to store the ciphertext.  */
1036afc6579bSmlelstv 	buf = cgd_getdata(sc, nbytes);
1037de8d1fd3Sriastradh 	if (buf == NULL)
1038de8d1fd3Sriastradh 		/* Out of memory: give up.  */
1039de8d1fd3Sriastradh 		return ENOMEM;
1040de8d1fd3Sriastradh 
1041de8d1fd3Sriastradh 	/* Encrypt the caller's data into the temporary buffer.  */
1042de8d1fd3Sriastradh 	cgd_cipher(sc, buf, va, nbytes, blkno, blksize, CGD_CIPHER_ENCRYPT);
1043de8d1fd3Sriastradh 
1044de8d1fd3Sriastradh 	/* Pass it on to the underlying disk device.  */
1045de8d1fd3Sriastradh 	error = bdev_dump(sc->sc_tdev, blkno, buf, nbytes);
1046de8d1fd3Sriastradh 
1047de8d1fd3Sriastradh 	/* Release the buffer.  */
1048067e9296Stnn 	cgd_putdata(sc, buf, nbytes);
1049de8d1fd3Sriastradh 
1050de8d1fd3Sriastradh 	/* Return any error from the underlying disk device.  */
1051de8d1fd3Sriastradh 	return error;
1052de8d1fd3Sriastradh }
1053de8d1fd3Sriastradh 
10544366a007Selric /* XXX: we should probably put these into dksubr.c, mostly */
1055a1bb10efSthorpej static int
cgdread(dev_t dev,struct uio * uio,int flags)1056168cd830Schristos cgdread(dev_t dev, struct uio *uio, int flags)
10574366a007Selric {
1058afc6579bSmlelstv 	struct	cgd_softc *sc;
10594366a007Selric 	struct	dk_softc *dksc;
10604366a007Selric 
106108ebead9Scegger 	DPRINTF_FOLLOW(("cgdread(0x%llx, %p, %d)\n",
106208ebead9Scegger 	    (unsigned long long)dev, uio, flags));
1063afc6579bSmlelstv 	sc = getcgd_softc(dev);
1064afc6579bSmlelstv 	if (sc == NULL)
1065afc6579bSmlelstv 		return ENXIO;
1066afc6579bSmlelstv 	dksc = &sc->sc_dksc;
10675f991650Smlelstv 	if (!DK_ATTACHED(dksc))
10684366a007Selric 		return ENXIO;
10694366a007Selric 	return physio(cgdstrategy, NULL, dev, B_READ, minphys, uio);
10704366a007Selric }
10714366a007Selric 
10724366a007Selric /* XXX: we should probably put these into dksubr.c, mostly */
1073a1bb10efSthorpej static int
cgdwrite(dev_t dev,struct uio * uio,int flags)1074168cd830Schristos cgdwrite(dev_t dev, struct uio *uio, int flags)
10754366a007Selric {
1076afc6579bSmlelstv 	struct	cgd_softc *sc;
10774366a007Selric 	struct	dk_softc *dksc;
10784366a007Selric 
107908ebead9Scegger 	DPRINTF_FOLLOW(("cgdwrite(0x%"PRIx64", %p, %d)\n", dev, uio, flags));
1080afc6579bSmlelstv 	sc = getcgd_softc(dev);
1081afc6579bSmlelstv 	if (sc == NULL)
1082afc6579bSmlelstv 		return ENXIO;
1083afc6579bSmlelstv 	dksc = &sc->sc_dksc;
10845f991650Smlelstv 	if (!DK_ATTACHED(dksc))
10854366a007Selric 		return ENXIO;
10864366a007Selric 	return physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio);
10874366a007Selric }
10884366a007Selric 
1089a1bb10efSthorpej static int
cgdioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)109053524e44Schristos cgdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
10914366a007Selric {
1092afc6579bSmlelstv 	struct	cgd_softc *sc;
10934366a007Selric 	struct	dk_softc *dksc;
10944366a007Selric 	int	part = DISKPART(dev);
10954366a007Selric 	int	pmask = 1 << part;
1096afc6579bSmlelstv 	int	error;
10974366a007Selric 
109808ebead9Scegger 	DPRINTF_FOLLOW(("cgdioctl(0x%"PRIx64", %ld, %p, %d, %p)\n",
109995e1ffb1Schristos 	    dev, cmd, data, flag, l));
11000f179f79Schristos 
11014366a007Selric 	switch (cmd) {
1102e0e27234Schristos 	case CGDIOCGET:
1103e0e27234Schristos 		return cgd_ioctl_get(dev, data, l);
11044366a007Selric 	case CGDIOCSET:
11054366a007Selric 	case CGDIOCCLR:
11064366a007Selric 		if ((flag & FWRITE) == 0)
11074366a007Selric 			return EBADF;
11080f179f79Schristos 		/* FALLTHROUGH */
11090f179f79Schristos 	default:
1110afc6579bSmlelstv 		sc = getcgd_softc(dev);
1111afc6579bSmlelstv 		if (sc == NULL)
1112afc6579bSmlelstv 			return ENXIO;
1113afc6579bSmlelstv 		dksc = &sc->sc_dksc;
11140f179f79Schristos 		break;
11154366a007Selric 	}
11164366a007Selric 
11174366a007Selric 	switch (cmd) {
11184366a007Selric 	case CGDIOCSET:
1119afc6579bSmlelstv 		cgd_busy(sc);
11205f991650Smlelstv 		if (DK_ATTACHED(dksc))
1121afc6579bSmlelstv 			error = EBUSY;
1122afc6579bSmlelstv 		else
1123afc6579bSmlelstv 			error = cgd_ioctl_set(sc, data, l);
1124afc6579bSmlelstv 		cgd_unbusy(sc);
1125afc6579bSmlelstv 		break;
11264366a007Selric 	case CGDIOCCLR:
1127afc6579bSmlelstv 		cgd_busy(sc);
1128afc6579bSmlelstv 		if (DK_BUSY(&sc->sc_dksc, pmask))
1129afc6579bSmlelstv 			error = EBUSY;
1130afc6579bSmlelstv 		else
1131afc6579bSmlelstv 			error = cgd_ioctl_clr(sc, l);
1132afc6579bSmlelstv 		cgd_unbusy(sc);
1133afc6579bSmlelstv 		break;
11345ad012e5Sjdolecek 	case DIOCGCACHE:
1135caccc812Sapb 	case DIOCCACHESYNC:
1136afc6579bSmlelstv 		cgd_busy(sc);
1137afc6579bSmlelstv 		if (!DK_ATTACHED(dksc)) {
1138afc6579bSmlelstv 			cgd_unbusy(sc);
1139afc6579bSmlelstv 			error = ENOENT;
1140afc6579bSmlelstv 			break;
1141afc6579bSmlelstv 		}
1142caccc812Sapb 		/*
1143caccc812Sapb 		 * We pass this call down to the underlying disk.
1144caccc812Sapb 		 */
1145afc6579bSmlelstv 		error = VOP_IOCTL(sc->sc_tvn, cmd, data, flag, l->l_cred);
1146afc6579bSmlelstv 		cgd_unbusy(sc);
1147afc6579bSmlelstv 		break;
1148ffcf681eSriastradh 	case DIOCGSECTORALIGN: {
1149ffcf681eSriastradh 		struct disk_sectoralign *dsa = data;
1150ffcf681eSriastradh 
1151afc6579bSmlelstv 		cgd_busy(sc);
1152afc6579bSmlelstv 		if (!DK_ATTACHED(dksc)) {
1153afc6579bSmlelstv 			cgd_unbusy(sc);
1154afc6579bSmlelstv 			error = ENOENT;
1155afc6579bSmlelstv 			break;
1156afc6579bSmlelstv 		}
1157ffcf681eSriastradh 
1158ffcf681eSriastradh 		/* Get the underlying disk's sector alignment.  */
1159afc6579bSmlelstv 		error = VOP_IOCTL(sc->sc_tvn, cmd, data, flag, l->l_cred);
1160afc6579bSmlelstv 		if (error) {
1161afc6579bSmlelstv 			cgd_unbusy(sc);
1162afc6579bSmlelstv 			break;
1163afc6579bSmlelstv 		}
1164ffcf681eSriastradh 
1165ffcf681eSriastradh 		/* Adjust for the disklabel partition if necessary.  */
1166ffcf681eSriastradh 		if (part != RAW_PART) {
1167ffcf681eSriastradh 			struct disklabel *lp = dksc->sc_dkdev.dk_label;
1168ffcf681eSriastradh 			daddr_t offset = lp->d_partitions[part].p_offset;
1169ffcf681eSriastradh 			uint32_t r = offset % dsa->dsa_alignment;
1170ffcf681eSriastradh 
1171ffcf681eSriastradh 			if (r < dsa->dsa_firstaligned)
1172ffcf681eSriastradh 				dsa->dsa_firstaligned = dsa->dsa_firstaligned
1173ffcf681eSriastradh 				    - r;
1174ffcf681eSriastradh 			else
1175ffcf681eSriastradh 				dsa->dsa_firstaligned = (dsa->dsa_firstaligned
1176ffcf681eSriastradh 				    + dsa->dsa_alignment) - r;
1177ffcf681eSriastradh 		}
1178afc6579bSmlelstv 		cgd_unbusy(sc);
1179afc6579bSmlelstv 		break;
1180ffcf681eSriastradh 	}
11810306f299Schristos 	case DIOCGSTRATEGY:
11820306f299Schristos 	case DIOCSSTRATEGY:
1183afc6579bSmlelstv 		if (!DK_ATTACHED(dksc)) {
1184afc6579bSmlelstv 			error = ENOENT;
1185afc6579bSmlelstv 			break;
1186afc6579bSmlelstv 		}
11870306f299Schristos 		/*FALLTHROUGH*/
11884366a007Selric 	default:
1189afc6579bSmlelstv 		error = dk_ioctl(dksc, dev, cmd, data, flag, l);
1190afc6579bSmlelstv 		break;
1191e0e27234Schristos 	case CGDIOCGET:
1192e0e27234Schristos 		KASSERT(0);
1193afc6579bSmlelstv 		error = EINVAL;
11944366a007Selric 	}
1195afc6579bSmlelstv 
1196afc6579bSmlelstv 	return error;
11974366a007Selric }
11984366a007Selric 
1199a1bb10efSthorpej static int
cgddump(dev_t dev,daddr_t blkno,void * va,size_t size)120053524e44Schristos cgddump(dev_t dev, daddr_t blkno, void *va, size_t size)
12014366a007Selric {
1202afc6579bSmlelstv 	struct	cgd_softc *sc;
12034366a007Selric 
120408ebead9Scegger 	DPRINTF_FOLLOW(("cgddump(0x%"PRIx64", %" PRId64 ", %p, %lu)\n",
120508ebead9Scegger 	    dev, blkno, va, (unsigned long)size));
1206afc6579bSmlelstv 	sc = getcgd_softc(dev);
1207afc6579bSmlelstv 	if (sc == NULL)
1208afc6579bSmlelstv 		return ENXIO;
1209afc6579bSmlelstv 	return dk_dump(&sc->sc_dksc, dev, blkno, va, size, DK_DUMP_RECURSIVE);
12104366a007Selric }
12114366a007Selric 
12124366a007Selric /*
12134366a007Selric  * XXXrcd:
12144366a007Selric  *  for now we hardcode the maximum key length.
12154366a007Selric  */
12164366a007Selric #define MAX_KEYSIZE	1024
12174366a007Selric 
121866f8c243Schristos static const struct {
121966f8c243Schristos 	const char *n;
122066f8c243Schristos 	int v;
122166f8c243Schristos 	int d;
122266f8c243Schristos } encblkno[] = {
122366f8c243Schristos 	{ "encblkno",  CGD_CIPHER_CBC_ENCBLKNO8, 1 },
122466f8c243Schristos 	{ "encblkno8", CGD_CIPHER_CBC_ENCBLKNO8, 1 },
122566f8c243Schristos 	{ "encblkno1", CGD_CIPHER_CBC_ENCBLKNO1, 8 },
122666f8c243Schristos };
122766f8c243Schristos 
12284366a007Selric /* ARGSUSED */
12294366a007Selric static int
cgd_ioctl_set(struct cgd_softc * sc,void * data,struct lwp * l)1230afc6579bSmlelstv cgd_ioctl_set(struct cgd_softc *sc, void *data, struct lwp *l)
12314366a007Selric {
12324366a007Selric 	struct	 cgd_ioctl *ci = data;
12334366a007Selric 	struct	 vnode *vp;
12344366a007Selric 	int	 ret;
123566f8c243Schristos 	size_t	 i;
1236810b552fScbiere 	size_t	 keybytes;			/* key length in bytes */
12379b0c1757Sdrochner 	const char *cp;
12388f6ed30dSdholland 	struct pathbuf *pb;
1239709b2e6fSchristos 	char	 *inbuf;
1240afc6579bSmlelstv 	struct dk_softc *dksc = &sc->sc_dksc;
12414366a007Selric 
12424366a007Selric 	cp = ci->ci_disk;
12438f6ed30dSdholland 
12448f6ed30dSdholland 	ret = pathbuf_copyin(ci->ci_disk, &pb);
12458f6ed30dSdholland 	if (ret != 0) {
12464366a007Selric 		return ret;
12478f6ed30dSdholland 	}
12485a52f2afSmlelstv 	ret = vn_bdev_openpath(pb, &vp, l);
12498f6ed30dSdholland 	pathbuf_destroy(pb);
12508f6ed30dSdholland 	if (ret != 0) {
12518f6ed30dSdholland 		return ret;
12528f6ed30dSdholland 	}
12534366a007Selric 
1254afc6579bSmlelstv 	inbuf = kmem_alloc(MAX_KEYSIZE, KM_SLEEP);
1255709b2e6fSchristos 
1256afc6579bSmlelstv 	if ((ret = cgdinit(sc, cp, vp, l)) != 0)
12574366a007Selric 		goto bail;
12584366a007Selric 
1259709b2e6fSchristos 	(void)memset(inbuf, 0, MAX_KEYSIZE);
12604366a007Selric 	ret = copyinstr(ci->ci_alg, inbuf, 256, NULL);
12614366a007Selric 	if (ret)
12624366a007Selric 		goto bail;
1263afc6579bSmlelstv 	sc->sc_cfuncs = cryptfuncs_find(inbuf);
1264afc6579bSmlelstv 	if (!sc->sc_cfuncs) {
12654366a007Selric 		ret = EINVAL;
12664366a007Selric 		goto bail;
12674366a007Selric 	}
12684366a007Selric 
1269810b552fScbiere 	(void)memset(inbuf, 0, MAX_KEYSIZE);
1270709b2e6fSchristos 	ret = copyinstr(ci->ci_ivmethod, inbuf, MAX_KEYSIZE, NULL);
12714366a007Selric 	if (ret)
12724366a007Selric 		goto bail;
127366f8c243Schristos 
127466f8c243Schristos 	for (i = 0; i < __arraycount(encblkno); i++)
127566f8c243Schristos 		if (strcmp(encblkno[i].n, inbuf) == 0)
127666f8c243Schristos 			break;
127766f8c243Schristos 
127866f8c243Schristos 	if (i == __arraycount(encblkno)) {
12794366a007Selric 		ret = EINVAL;
12804366a007Selric 		goto bail;
12814366a007Selric 	}
12824366a007Selric 
1283b912bfccSdan 	keybytes = ci->ci_keylen / 8 + 1;
1284b912bfccSdan 	if (keybytes > MAX_KEYSIZE) {
12854366a007Selric 		ret = EINVAL;
12864366a007Selric 		goto bail;
12874366a007Selric 	}
128866f8c243Schristos 
1289709b2e6fSchristos 	(void)memset(inbuf, 0, MAX_KEYSIZE);
1290b912bfccSdan 	ret = copyin(ci->ci_key, inbuf, keybytes);
12914366a007Selric 	if (ret)
12924366a007Selric 		goto bail;
12934366a007Selric 
1294afc6579bSmlelstv 	sc->sc_cdata.cf_blocksize = ci->ci_blocksize;
1295afc6579bSmlelstv 	sc->sc_cdata.cf_mode = encblkno[i].v;
12965b0a15b1Sriastradh 
12975b0a15b1Sriastradh 	/*
12985b0a15b1Sriastradh 	 * Print a warning if the user selected the legacy encblkno8
12995b0a15b1Sriastradh 	 * mistake, and reject it altogether for ciphers that it
13005b0a15b1Sriastradh 	 * doesn't apply to.
13015b0a15b1Sriastradh 	 */
13025b0a15b1Sriastradh 	if (encblkno[i].v != CGD_CIPHER_CBC_ENCBLKNO1) {
13035b0a15b1Sriastradh 		if (strcmp(sc->sc_cfuncs->cf_name, "aes-cbc") &&
13045b0a15b1Sriastradh 		    strcmp(sc->sc_cfuncs->cf_name, "3des-cbc") &&
1305c145b373Sriastradh 		    strcmp(sc->sc_cfuncs->cf_name, "blowfish-cbc")) {
13065b0a15b1Sriastradh 			log(LOG_WARNING, "cgd: %s only makes sense for cbc,"
13075b0a15b1Sriastradh 			    " not for %s; ignoring\n",
13085b0a15b1Sriastradh 			    encblkno[i].n, sc->sc_cfuncs->cf_name);
13095b0a15b1Sriastradh 			sc->sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO1;
13105b0a15b1Sriastradh 		} else {
13115b0a15b1Sriastradh 			log(LOG_WARNING, "cgd: enabling legacy encblkno8\n");
13125b0a15b1Sriastradh 		}
13135b0a15b1Sriastradh 	}
13145b0a15b1Sriastradh 
1315afc6579bSmlelstv 	sc->sc_cdata.cf_keylen = ci->ci_keylen;
1316afc6579bSmlelstv 	sc->sc_cdata.cf_priv = sc->sc_cfuncs->cf_init(ci->ci_keylen, inbuf,
1317afc6579bSmlelstv 	    &sc->sc_cdata.cf_blocksize);
1318afc6579bSmlelstv 	if (sc->sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE) {
131918975112Schristos 	    log(LOG_WARNING, "cgd: Disallowed cipher with blocksize %zu > %u\n",
1320afc6579bSmlelstv 		sc->sc_cdata.cf_blocksize, CGD_MAXBLOCKSIZE);
1321afc6579bSmlelstv 	    sc->sc_cdata.cf_priv = NULL;
132218975112Schristos 	}
132318975112Schristos 
132466f8c243Schristos 	/*
132566f8c243Schristos 	 * The blocksize is supposed to be in bytes. Unfortunately originally
132666f8c243Schristos 	 * it was expressed in bits. For compatibility we maintain encblkno
132766f8c243Schristos 	 * and encblkno8.
132866f8c243Schristos 	 */
1329afc6579bSmlelstv 	sc->sc_cdata.cf_blocksize /= encblkno[i].d;
1330f6ff1e4bSriastradh 	(void)explicit_memset(inbuf, 0, MAX_KEYSIZE);
1331afc6579bSmlelstv 	if (!sc->sc_cdata.cf_priv) {
13324366a007Selric 		ret = EINVAL;		/* XXX is this the right error? */
13334366a007Selric 		goto bail;
13344366a007Selric 	}
1335afc6579bSmlelstv 	kmem_free(inbuf, MAX_KEYSIZE);
13364366a007Selric 
13371af75d44Schristos 	bufq_alloc(&dksc->sc_bufq, "fcfs", 0);
1338befeae89Selric 
1339067e9296Stnn 	sc->sc_data = kmem_alloc(MAXPHYS, KM_SLEEP);
1340afc6579bSmlelstv 	sc->sc_data_used = false;
1341befeae89Selric 
13425f991650Smlelstv 	/* Attach the disk. */
13435f991650Smlelstv 	dk_attach(dksc);
13445f991650Smlelstv 	disk_attach(&dksc->sc_dkdev);
13454366a007Selric 
13461af75d44Schristos 	disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
134799c563ccSelric 
13485cb036f6Syamt 	/* Discover wedges on this disk. */
13491af75d44Schristos 	dkwedge_discover(&dksc->sc_dkdev);
13505cb036f6Syamt 
13514366a007Selric 	return 0;
13524366a007Selric 
13534366a007Selric bail:
1354afc6579bSmlelstv 	kmem_free(inbuf, MAX_KEYSIZE);
1355a9ca7a37Sad 	(void)vn_close(vp, FREAD|FWRITE, l->l_cred);
13564366a007Selric 	return ret;
13574366a007Selric }
13584366a007Selric 
13594366a007Selric /* ARGSUSED */
13604366a007Selric static int
cgd_ioctl_clr(struct cgd_softc * sc,struct lwp * l)1361afc6579bSmlelstv cgd_ioctl_clr(struct cgd_softc *sc, struct lwp *l)
13624366a007Selric {
1363afc6579bSmlelstv 	struct	dk_softc *dksc = &sc->sc_dksc;
13641b379d7aSdyoung 
13655f991650Smlelstv 	if (!DK_ATTACHED(dksc))
13661b379d7aSdyoung 		return ENXIO;
1367befeae89Selric 
13685cb036f6Syamt 	/* Delete all of our wedges. */
13691af75d44Schristos 	dkwedge_delall(&dksc->sc_dkdev);
13705cb036f6Syamt 
1371befeae89Selric 	/* Kill off any queued buffers. */
13727874349bSmlelstv 	dk_drain(dksc);
13731af75d44Schristos 	bufq_free(dksc->sc_bufq);
13744366a007Selric 
1375afc6579bSmlelstv 	(void)vn_close(sc->sc_tvn, FREAD|FWRITE, l->l_cred);
1376afc6579bSmlelstv 	sc->sc_cfuncs->cf_destroy(sc->sc_cdata.cf_priv);
1377afc6579bSmlelstv 	kmem_free(sc->sc_tpath, sc->sc_tpathlen);
1378067e9296Stnn 	kmem_free(sc->sc_data, MAXPHYS);
1379afc6579bSmlelstv 	sc->sc_data_used = false;
13805f991650Smlelstv 	dk_detach(dksc);
13811af75d44Schristos 	disk_detach(&dksc->sc_dkdev);
13824366a007Selric 
13834366a007Selric 	return 0;
13844366a007Selric }
13854366a007Selric 
13864366a007Selric static int
cgd_ioctl_get(dev_t dev,void * data,struct lwp * l)13870f179f79Schristos cgd_ioctl_get(dev_t dev, void *data, struct lwp *l)
13880f179f79Schristos {
1389afc6579bSmlelstv 	struct cgd_softc *sc;
13900f179f79Schristos 	struct cgd_user *cgu;
1391afc6579bSmlelstv 	int unit, error;
13920f179f79Schristos 
13930f179f79Schristos 	unit = CGDUNIT(dev);
13940f179f79Schristos 	cgu = (struct cgd_user *)data;
13950f179f79Schristos 
13960f179f79Schristos 	DPRINTF_FOLLOW(("cgd_ioctl_get(0x%"PRIx64", %d, %p, %p)\n",
13970f179f79Schristos 			   dev, unit, data, l));
13980f179f79Schristos 
1399afc6579bSmlelstv 	/* XXX, we always return this units data, so if cgu_unit is
1400afc6579bSmlelstv 	 * not -1, that field doesn't match the rest
1401afc6579bSmlelstv 	 */
14020f179f79Schristos 	if (cgu->cgu_unit == -1)
14030f179f79Schristos 		cgu->cgu_unit = unit;
14040f179f79Schristos 
14050f179f79Schristos 	if (cgu->cgu_unit < 0)
14060f179f79Schristos 		return EINVAL;	/* XXX: should this be ENXIO? */
14070f179f79Schristos 
1408afc6579bSmlelstv 	error = cgd_lock(false);
1409afc6579bSmlelstv 	if (error)
1410afc6579bSmlelstv 		return error;
1411afc6579bSmlelstv 
1412afc6579bSmlelstv 	sc = device_lookup_private(&cgd_cd, unit);
1413afc6579bSmlelstv 	if (sc == NULL || !DK_ATTACHED(&sc->sc_dksc)) {
14140f179f79Schristos 		cgu->cgu_dev = 0;
14150f179f79Schristos 		cgu->cgu_alg[0] = '\0';
14160f179f79Schristos 		cgu->cgu_blocksize = 0;
14170f179f79Schristos 		cgu->cgu_mode = 0;
14180f179f79Schristos 		cgu->cgu_keylen = 0;
14190f179f79Schristos 	}
14200f179f79Schristos 	else {
1421afc6579bSmlelstv 		mutex_enter(&sc->sc_lock);
1422afc6579bSmlelstv 		cgu->cgu_dev = sc->sc_tdev;
1423afc6579bSmlelstv 		strncpy(cgu->cgu_alg, sc->sc_cfuncs->cf_name,
14240f179f79Schristos 		    sizeof(cgu->cgu_alg));
1425afc6579bSmlelstv 		cgu->cgu_blocksize = sc->sc_cdata.cf_blocksize;
1426afc6579bSmlelstv 		cgu->cgu_mode = sc->sc_cdata.cf_mode;
1427afc6579bSmlelstv 		cgu->cgu_keylen = sc->sc_cdata.cf_keylen;
1428afc6579bSmlelstv 		mutex_exit(&sc->sc_lock);
14290f179f79Schristos 	}
1430afc6579bSmlelstv 
1431afc6579bSmlelstv 	cgd_unlock();
14320f179f79Schristos 	return 0;
14330f179f79Schristos }
14340f179f79Schristos 
14350f179f79Schristos static int
cgdinit(struct cgd_softc * sc,const char * cpath,struct vnode * vp,struct lwp * l)1436afc6579bSmlelstv cgdinit(struct cgd_softc *sc, const char *cpath, struct vnode *vp,
143795e1ffb1Schristos 	struct lwp *l)
14384366a007Selric {
14391af75d44Schristos 	struct	disk_geom *dg;
14404366a007Selric 	int	ret;
1441709b2e6fSchristos 	char	*tmppath;
14429fc82cfcSchristos 	uint64_t psize;
14439fc82cfcSchristos 	unsigned secsize;
1444afc6579bSmlelstv 	struct dk_softc *dksc = &sc->sc_dksc;
14454366a007Selric 
1446afc6579bSmlelstv 	sc->sc_tvn = vp;
1447afc6579bSmlelstv 	sc->sc_tpath = NULL;
14484366a007Selric 
1449afc6579bSmlelstv 	tmppath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1450afc6579bSmlelstv 	ret = copyinstr(cpath, tmppath, MAXPATHLEN, &sc->sc_tpathlen);
14514366a007Selric 	if (ret)
14524366a007Selric 		goto bail;
1453afc6579bSmlelstv 	sc->sc_tpath = kmem_alloc(sc->sc_tpathlen, KM_SLEEP);
1454afc6579bSmlelstv 	memcpy(sc->sc_tpath, tmppath, sc->sc_tpathlen);
14554366a007Selric 
1456afc6579bSmlelstv 	sc->sc_tdev = vp->v_rdev;
14574366a007Selric 
14589fc82cfcSchristos 	if ((ret = getdisksize(vp, &psize, &secsize)) != 0)
14594366a007Selric 		goto bail;
14604366a007Selric 
14619fc82cfcSchristos 	if (psize == 0) {
14624366a007Selric 		ret = ENODEV;
14634366a007Selric 		goto bail;
14644366a007Selric 	}
14654366a007Selric 
14664366a007Selric 	/*
14674366a007Selric 	 * XXX here we should probe the underlying device.  If we
14684366a007Selric 	 *     are accessing a partition of type RAW_PART, then
14694366a007Selric 	 *     we should populate our initial geometry with the
14704366a007Selric 	 *     geometry that we discover from the device.
14714366a007Selric 	 */
14721af75d44Schristos 	dg = &dksc->sc_dkdev.dk_geom;
14731af75d44Schristos 	memset(dg, 0, sizeof(*dg));
14741af75d44Schristos 	dg->dg_secperunit = psize;
14759c6a5e26Smlelstv 	dg->dg_secsize = secsize;
14761af75d44Schristos 	dg->dg_ntracks = 1;
14779c6a5e26Smlelstv 	dg->dg_nsectors = 1024 * 1024 / dg->dg_secsize;
14781af75d44Schristos 	dg->dg_ncylinders = dg->dg_secperunit / dg->dg_nsectors;
14794366a007Selric 
14804366a007Selric bail:
1481afc6579bSmlelstv 	kmem_free(tmppath, MAXPATHLEN);
1482afc6579bSmlelstv 	if (ret && sc->sc_tpath)
1483afc6579bSmlelstv 		kmem_free(sc->sc_tpath, sc->sc_tpathlen);
14844366a007Selric 	return ret;
14854366a007Selric }
14864366a007Selric 
14874366a007Selric /*
14884366a007Selric  * Our generic cipher entry point.  This takes care of the
14894366a007Selric  * IV mode and passes off the work to the specific cipher.
14904366a007Selric  * We implement here the IV method ``encrypted block
14914366a007Selric  * number''.
14924366a007Selric  *
14934366a007Selric  * XXXrcd: for now we rely on our own crypto framework defined
14944366a007Selric  *         in dev/cgd_crypto.c.  This will change when we
14954366a007Selric  *         get a generic kernel crypto framework.
14964366a007Selric  */
14974366a007Selric 
14984366a007Selric static void
blkno2blkno_buf(char * sbuf,daddr_t blkno)14999db2752fSxtraeme blkno2blkno_buf(char *sbuf, daddr_t blkno)
15004366a007Selric {
15014366a007Selric 	int	i;
15024366a007Selric 
15034366a007Selric 	/* Set up the blkno in blkno_buf, here we do not care much
15044366a007Selric 	 * about the final layout of the information as long as we
15054366a007Selric 	 * can guarantee that each sector will have a different IV
15064366a007Selric 	 * and that the endianness of the machine will not affect
15074366a007Selric 	 * the representation that we have chosen.
15084366a007Selric 	 *
15094366a007Selric 	 * We choose this representation, because it does not rely
15104366a007Selric 	 * on the size of buf (which is the blocksize of the cipher),
15114366a007Selric 	 * but allows daddr_t to grow without breaking existing
15124366a007Selric 	 * disks.
15134366a007Selric 	 *
15144366a007Selric 	 * Note that blkno2blkno_buf does not take a size as input,
15154366a007Selric 	 * and hence must be called on a pre-zeroed buffer of length
15164366a007Selric 	 * greater than or equal to sizeof(daddr_t).
15174366a007Selric 	 */
15184366a007Selric 	for (i=0; i < sizeof(daddr_t); i++) {
15199db2752fSxtraeme 		*sbuf++ = blkno & 0xff;
15204366a007Selric 		blkno >>= 8;
15214366a007Selric 	}
15224366a007Selric }
15234366a007Selric 
1524afc6579bSmlelstv static struct cpu_info *
cgd_cpu(struct cgd_softc * sc)1525afc6579bSmlelstv cgd_cpu(struct cgd_softc *sc)
1526afc6579bSmlelstv {
1527afc6579bSmlelstv 	struct cgd_worker *cw = sc->sc_worker;
1528afc6579bSmlelstv 	struct cpu_info *ci = NULL;
1529afc6579bSmlelstv 	u_int cidx, i;
1530afc6579bSmlelstv 
1531afc6579bSmlelstv 	if (cw->cw_busy == 0) {
1532afc6579bSmlelstv 		cw->cw_last = cpu_index(curcpu());
1533afc6579bSmlelstv 		return NULL;
1534afc6579bSmlelstv 	}
1535afc6579bSmlelstv 
1536afc6579bSmlelstv 	for (i=0, cidx = cw->cw_last+1; i<maxcpus; ++i, ++cidx) {
1537afc6579bSmlelstv 		if (cidx >= maxcpus)
1538afc6579bSmlelstv 			cidx = 0;
1539afc6579bSmlelstv 		ci = cpu_lookup(cidx);
1540afc6579bSmlelstv 		if (ci) {
1541afc6579bSmlelstv 			cw->cw_last = cidx;
1542afc6579bSmlelstv 			break;
1543afc6579bSmlelstv 		}
1544afc6579bSmlelstv 	}
1545afc6579bSmlelstv 
1546afc6579bSmlelstv 	return ci;
1547afc6579bSmlelstv }
1548afc6579bSmlelstv 
15494366a007Selric static void
cgd_enqueue(struct cgd_softc * sc,struct cgd_xfer * cx)1550afc6579bSmlelstv cgd_enqueue(struct cgd_softc *sc, struct cgd_xfer *cx)
1551afc6579bSmlelstv {
1552afc6579bSmlelstv 	struct cgd_worker *cw = sc->sc_worker;
1553afc6579bSmlelstv 	struct cpu_info *ci;
1554afc6579bSmlelstv 
1555afc6579bSmlelstv 	mutex_enter(&cw->cw_lock);
1556afc6579bSmlelstv 	ci = cgd_cpu(sc);
1557afc6579bSmlelstv 	cw->cw_busy++;
1558afc6579bSmlelstv 	mutex_exit(&cw->cw_lock);
1559afc6579bSmlelstv 
1560afc6579bSmlelstv 	workqueue_enqueue(cw->cw_wq, &cx->cx_work, ci);
1561afc6579bSmlelstv }
1562afc6579bSmlelstv 
1563afc6579bSmlelstv static void
cgd_process(struct work * wk,void * arg)1564afc6579bSmlelstv cgd_process(struct work *wk, void *arg)
1565afc6579bSmlelstv {
1566afc6579bSmlelstv 	struct cgd_xfer *cx = (struct cgd_xfer *)wk;
1567afc6579bSmlelstv 	struct cgd_softc *sc = cx->cx_sc;
1568afc6579bSmlelstv 	struct cgd_worker *cw = sc->sc_worker;
1569afc6579bSmlelstv 
1570afc6579bSmlelstv 	cgd_cipher(sc, cx->cx_dstv, cx->cx_srcv, cx->cx_len,
1571afc6579bSmlelstv 	    cx->cx_blkno, cx->cx_secsize, cx->cx_dir);
1572afc6579bSmlelstv 
1573afc6579bSmlelstv 	if (cx->cx_dir == CGD_CIPHER_ENCRYPT) {
1574afc6579bSmlelstv 		cgd_diskstart2(sc, cx);
1575afc6579bSmlelstv 	} else {
1576afc6579bSmlelstv 		cgd_iodone2(sc, cx);
1577afc6579bSmlelstv 	}
1578afc6579bSmlelstv 
1579afc6579bSmlelstv 	mutex_enter(&cw->cw_lock);
1580afc6579bSmlelstv 	if (cw->cw_busy > 0)
1581afc6579bSmlelstv 		cw->cw_busy--;
1582afc6579bSmlelstv 	mutex_exit(&cw->cw_lock);
1583afc6579bSmlelstv }
1584afc6579bSmlelstv 
1585afc6579bSmlelstv static void
cgd_cipher(struct cgd_softc * sc,void * dstv,const void * srcv,size_t len,daddr_t blkno,size_t secsize,int dir)1586f7a9d62bSriastradh cgd_cipher(struct cgd_softc *sc, void *dstv, const void *srcv,
15874366a007Selric     size_t len, daddr_t blkno, size_t secsize, int dir)
15884366a007Selric {
158953524e44Schristos 	char		*dst = dstv;
1590f7a9d62bSriastradh 	const char	*src = srcv;
1591afc6579bSmlelstv 	cfunc_cipher	*cipher = sc->sc_cfuncs->cf_cipher;
1592afc6579bSmlelstv 	size_t		blocksize = sc->sc_cdata.cf_blocksize;
15939c6a5e26Smlelstv 	size_t		todo;
1594ab834bdaSriastradh 	char		blkno_buf[CGD_MAXBLOCKSIZE] __aligned(CGD_BLOCKALIGN);
15954366a007Selric 
15964366a007Selric 	DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir));
15974366a007Selric 
15985b0a15b1Sriastradh 	if (sc->sc_cdata.cf_mode == CGD_CIPHER_CBC_ENCBLKNO8)
15995b0a15b1Sriastradh 		blocksize /= 8;
16005b0a15b1Sriastradh 
16014754462eSriastradh 	KASSERT(len % blocksize == 0);
16024366a007Selric 	/* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */
16034754462eSriastradh 	KASSERT(sizeof(daddr_t) <= blocksize);
16044754462eSriastradh 	KASSERT(blocksize <= CGD_MAXBLOCKSIZE);
16054366a007Selric 
16069c6a5e26Smlelstv 	for (; len > 0; len -= todo) {
16079c6a5e26Smlelstv 		todo = MIN(len, secsize);
16089c6a5e26Smlelstv 
1609f026e979Schristos 		memset(blkno_buf, 0x0, blocksize);
16104366a007Selric 		blkno2blkno_buf(blkno_buf, blkno);
16114366a007Selric 		IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf",
1612f026e979Schristos 		    blkno_buf, blocksize));
1613b21f21dfSalnsn 
16145b0a15b1Sriastradh 		/*
16155b0a15b1Sriastradh 		 * Handle bollocksed up encblkno8 mistake.  We used to
16165b0a15b1Sriastradh 		 * compute the encryption of a zero block with blkno as
16175b0a15b1Sriastradh 		 * the CBC IV -- except in an early mistake arising
16185b0a15b1Sriastradh 		 * from bit/byte confusion, we actually computed the
16195b0a15b1Sriastradh 		 * encryption of the last of _eight_ zero blocks under
16205b0a15b1Sriastradh 		 * CBC as the CBC IV.
16215b0a15b1Sriastradh 		 *
16225b0a15b1Sriastradh 		 * Encrypting the block number is handled inside the
16235b0a15b1Sriastradh 		 * cipher dispatch now (even though in practice, both
16245b0a15b1Sriastradh 		 * CBC and XTS will do the same thing), so we have to
16255b0a15b1Sriastradh 		 * simulate the block number that would yield the same
16265b0a15b1Sriastradh 		 * result.  So we encrypt _six_ zero blocks -- the
16275b0a15b1Sriastradh 		 * first one and the last one are handled inside the
16285b0a15b1Sriastradh 		 * cipher dispatch.
16295b0a15b1Sriastradh 		 */
16305b0a15b1Sriastradh 		if (sc->sc_cdata.cf_mode == CGD_CIPHER_CBC_ENCBLKNO8) {
16315b0a15b1Sriastradh 			static const uint8_t zero[CGD_MAXBLOCKSIZE];
16325b0a15b1Sriastradh 			uint8_t iv[CGD_MAXBLOCKSIZE];
16335b0a15b1Sriastradh 
16345b0a15b1Sriastradh 			memcpy(iv, blkno_buf, blocksize);
16355b0a15b1Sriastradh 			cipher(sc->sc_cdata.cf_priv, blkno_buf, zero,
16365b0a15b1Sriastradh 			    6*blocksize, iv, CGD_CIPHER_ENCRYPT);
16375b0a15b1Sriastradh 			memmove(blkno_buf, blkno_buf + 5*blocksize, blocksize);
16385b0a15b1Sriastradh 		}
16395b0a15b1Sriastradh 
16404754462eSriastradh 		cipher(sc->sc_cdata.cf_priv, dst, src, todo, blkno_buf, dir);
16414366a007Selric 
16429c6a5e26Smlelstv 		dst += todo;
16439c6a5e26Smlelstv 		src += todo;
16444366a007Selric 		blkno++;
16454366a007Selric 	}
16464366a007Selric }
16474366a007Selric 
16484366a007Selric #ifdef DEBUG
16494366a007Selric static void
hexprint(const char * start,void * buf,int len)165031924c84Sdrochner hexprint(const char *start, void *buf, int len)
16514366a007Selric {
16524366a007Selric 	char	*c = buf;
16534366a007Selric 
165408c4e556Sriastradh 	KASSERTMSG(len >= 0, "hexprint: called with len < 0");
16554366a007Selric 	printf("%s: len=%06d 0x", start, len);
16564366a007Selric 	while (len--)
1657810b552fScbiere 		printf("%02x", (unsigned char) *c++);
16584366a007Selric }
16594366a007Selric #endif
16607147ed32Shaad 
1661b21f21dfSalnsn static void
cgd_selftest(void)166249fd8cb3Sriastradh cgd_selftest(void)
1663b21f21dfSalnsn {
1664afc6579bSmlelstv 	struct cgd_softc sc;
1665b21f21dfSalnsn 	void *buf;
1666b21f21dfSalnsn 
1667b21f21dfSalnsn 	for (size_t i = 0; i < __arraycount(selftests); i++) {
1668b21f21dfSalnsn 		const char *alg = selftests[i].alg;
16695b0a15b1Sriastradh 		int encblkno8 = selftests[i].encblkno8;
1670b21f21dfSalnsn 		const uint8_t *key = selftests[i].key;
1671b21f21dfSalnsn 		int keylen = selftests[i].keylen;
1672b21f21dfSalnsn 		int txtlen = selftests[i].txtlen;
1673b21f21dfSalnsn 
1674c484a56fSjmcneill 		aprint_debug("cgd: self-test %s-%d%s\n", alg, keylen,
16755b0a15b1Sriastradh 		    encblkno8 ? " (encblkno8)" : "");
1676b21f21dfSalnsn 
1677afc6579bSmlelstv 		memset(&sc, 0, sizeof(sc));
1678b21f21dfSalnsn 
1679afc6579bSmlelstv 		sc.sc_cfuncs = cryptfuncs_find(alg);
1680afc6579bSmlelstv 		if (sc.sc_cfuncs == NULL)
1681b21f21dfSalnsn 			panic("%s not implemented", alg);
1682b21f21dfSalnsn 
1683afc6579bSmlelstv 		sc.sc_cdata.cf_blocksize = 8 * selftests[i].blocksize;
16845b0a15b1Sriastradh 		sc.sc_cdata.cf_mode = encblkno8 ? CGD_CIPHER_CBC_ENCBLKNO8 :
16855b0a15b1Sriastradh 		    CGD_CIPHER_CBC_ENCBLKNO1;
1686afc6579bSmlelstv 		sc.sc_cdata.cf_keylen = keylen;
1687b21f21dfSalnsn 
1688afc6579bSmlelstv 		sc.sc_cdata.cf_priv = sc.sc_cfuncs->cf_init(keylen,
1689afc6579bSmlelstv 		    key, &sc.sc_cdata.cf_blocksize);
1690afc6579bSmlelstv 		if (sc.sc_cdata.cf_priv == NULL)
1691b21f21dfSalnsn 			panic("cf_priv is NULL");
1692afc6579bSmlelstv 		if (sc.sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE)
1693afc6579bSmlelstv 			panic("bad block size %zu", sc.sc_cdata.cf_blocksize);
1694b21f21dfSalnsn 
16955b0a15b1Sriastradh 		if (!encblkno8)
1696afc6579bSmlelstv 			sc.sc_cdata.cf_blocksize /= 8;
1697b21f21dfSalnsn 
1698067e9296Stnn 		buf = kmem_alloc(txtlen, KM_SLEEP);
1699b21f21dfSalnsn 		memcpy(buf, selftests[i].ptxt, txtlen);
1700b21f21dfSalnsn 
1701afc6579bSmlelstv 		cgd_cipher(&sc, buf, buf, txtlen, selftests[i].blkno,
1702b21f21dfSalnsn 				selftests[i].secsize, CGD_CIPHER_ENCRYPT);
17034bf72725Sriastradh 		if (memcmp(buf, selftests[i].ctxt, txtlen) != 0) {
17044bf72725Sriastradh 			hexdump(printf, "was", buf, txtlen);
17054bf72725Sriastradh 			hexdump(printf, "exp", selftests[i].ctxt, txtlen);
1706e4d0ac73Sriastradh 			panic("cgd %s-%d encryption is broken [%zu]",
1707e4d0ac73Sriastradh 			    selftests[i].alg, keylen, i);
17084bf72725Sriastradh 		}
1709b21f21dfSalnsn 
1710afc6579bSmlelstv 		cgd_cipher(&sc, buf, buf, txtlen, selftests[i].blkno,
1711b21f21dfSalnsn 				selftests[i].secsize, CGD_CIPHER_DECRYPT);
17124bf72725Sriastradh 		if (memcmp(buf, selftests[i].ptxt, txtlen) != 0) {
17134bf72725Sriastradh 			hexdump(printf, "was", buf, txtlen);
17144bf72725Sriastradh 			hexdump(printf, "exp", selftests[i].ptxt, txtlen);
1715e4d0ac73Sriastradh 			panic("cgd %s-%d decryption is broken [%zu]",
1716e4d0ac73Sriastradh 			    selftests[i].alg, keylen, i);
17174bf72725Sriastradh 		}
1718b21f21dfSalnsn 
1719067e9296Stnn 		kmem_free(buf, txtlen);
1720afc6579bSmlelstv 		sc.sc_cfuncs->cf_destroy(sc.sc_cdata.cf_priv);
1721b21f21dfSalnsn 	}
1722b21f21dfSalnsn 
1723c484a56fSjmcneill 	aprint_debug("cgd: self-tests passed\n");
1724b21f21dfSalnsn }
1725b21f21dfSalnsn 
1726*7c69fd13Sriastradh MODULE(MODULE_CLASS_DRIVER, cgd, "blowfish,des,dk_subr,bufq_fcfs");
1727b4a3a8f3Sjruoho 
1728b4a3a8f3Sjruoho #ifdef _MODULE
172908d9aa56Sdyoung CFDRIVER_DECL(cgd, DV_DISK, NULL);
17309e4ecfb0Spgoyette 
17319e4ecfb0Spgoyette devmajor_t cgd_bmajor = -1, cgd_cmajor = -1;
1732b4a3a8f3Sjruoho #endif
17337147ed32Shaad 
17347147ed32Shaad static int
cgd_modcmd(modcmd_t cmd,void * arg)17357147ed32Shaad cgd_modcmd(modcmd_t cmd, void *arg)
17367147ed32Shaad {
1737822c138dSmartin 	int error = 0;
1738b4a3a8f3Sjruoho 
17397147ed32Shaad 	switch (cmd) {
17407147ed32Shaad 	case MODULE_CMD_INIT:
1741b4a3a8f3Sjruoho #ifdef _MODULE
1742afc6579bSmlelstv 		mutex_init(&cgd_spawning_mtx, MUTEX_DEFAULT, IPL_NONE);
1743afc6579bSmlelstv 		cv_init(&cgd_spawning_cv, "cgspwn");
1744afc6579bSmlelstv 
17459e4ecfb0Spgoyette 		/*
17469e4ecfb0Spgoyette 		 * Attach the {b,c}devsw's
17479e4ecfb0Spgoyette 		 */
17489e4ecfb0Spgoyette 		error = devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
17499e4ecfb0Spgoyette 		    &cgd_cdevsw, &cgd_cmajor);
175008d9aa56Sdyoung 		if (error) {
17519e4ecfb0Spgoyette 			aprint_error("%s: unable to attach %s devsw, "
17529e4ecfb0Spgoyette 			    "error %d", __func__, cgd_cd.cd_name, error);
175308d9aa56Sdyoung 			break;
175408d9aa56Sdyoung 		}
175597f8debdSpgoyette 
175697f8debdSpgoyette 		/*
175797f8debdSpgoyette 		 * Attach to autoconf database
175897f8debdSpgoyette 		 */
175997f8debdSpgoyette 		error = config_cfdriver_attach(&cgd_cd);
176097f8debdSpgoyette 		if (error) {
176197f8debdSpgoyette 			devsw_detach(&cgd_bdevsw, &cgd_cdevsw);
176297f8debdSpgoyette 			aprint_error("%s: unable to register cfdriver for"
176397f8debdSpgoyette 			    "%s, error %d\n", __func__, cgd_cd.cd_name, error);
176497f8debdSpgoyette 			break;
176597f8debdSpgoyette 		}
176697f8debdSpgoyette 
176797f8debdSpgoyette 		error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
176897f8debdSpgoyette 	        if (error) {
176997f8debdSpgoyette 			config_cfdriver_detach(&cgd_cd);
177097f8debdSpgoyette 			devsw_detach(&cgd_bdevsw, &cgd_cdevsw);
177197f8debdSpgoyette 			aprint_error("%s: unable to register cfattach for"
177297f8debdSpgoyette 			    "%s, error %d\n", __func__, cgd_cd.cd_name, error);
177397f8debdSpgoyette 			break;
177497f8debdSpgoyette 		}
1775b4a3a8f3Sjruoho #endif
17767147ed32Shaad 		break;
17777147ed32Shaad 
17787147ed32Shaad 	case MODULE_CMD_FINI:
1779b4a3a8f3Sjruoho #ifdef _MODULE
17809e4ecfb0Spgoyette 		/*
178197f8debdSpgoyette 		 * Remove device from autoconf database
17829e4ecfb0Spgoyette 		 */
17839e4ecfb0Spgoyette 		error = config_cfattach_detach(cgd_cd.cd_name, &cgd_ca);
17849e4ecfb0Spgoyette 		if (error) {
17859e4ecfb0Spgoyette 			aprint_error("%s: failed to detach %s cfattach, "
17869e4ecfb0Spgoyette 			    "error %d\n", __func__, cgd_cd.cd_name, error);
17879e4ecfb0Spgoyette  			break;
17889e4ecfb0Spgoyette 		}
17899e4ecfb0Spgoyette 		error = config_cfdriver_detach(&cgd_cd);
17909e4ecfb0Spgoyette 		if (error) {
1791106cffc3Spgoyette 			(void)config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
17929e4ecfb0Spgoyette 			aprint_error("%s: failed to detach %s cfdriver, "
17939e4ecfb0Spgoyette 			    "error %d\n", __func__, cgd_cd.cd_name, error);
17949e4ecfb0Spgoyette 			break;
17959e4ecfb0Spgoyette 		}
1796afc6579bSmlelstv 
179797f8debdSpgoyette 		/*
179897f8debdSpgoyette 		 * Remove {b,c}devsw's
179997f8debdSpgoyette 		 */
180097f8debdSpgoyette 		devsw_detach(&cgd_bdevsw, &cgd_cdevsw);
180197f8debdSpgoyette 
1802afc6579bSmlelstv 		cv_destroy(&cgd_spawning_cv);
1803afc6579bSmlelstv 		mutex_destroy(&cgd_spawning_mtx);
1804b4a3a8f3Sjruoho #endif
18057147ed32Shaad 		break;
18067147ed32Shaad 
18077147ed32Shaad 	case MODULE_CMD_STAT:
18089e4ecfb0Spgoyette 		error = ENOTTY;
18099e4ecfb0Spgoyette 		break;
18107147ed32Shaad 	default:
18119e4ecfb0Spgoyette 		error = ENOTTY;
18129e4ecfb0Spgoyette 		break;
18137147ed32Shaad 	}
18147147ed32Shaad 
18157147ed32Shaad 	return error;
18167147ed32Shaad }
1817