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