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