cgd.c revision 1.114.4.6 1 1.114.4.6 pgoyette /* $NetBSD: cgd.c,v 1.114.4.6 2017/04/29 10:50:46 pgoyette 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.114.4.6 pgoyette __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.114.4.6 2017/04/29 10:50:46 pgoyette 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.1 elric #include <sys/malloc.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.1 elric
55 1.1 elric #include <dev/dkvar.h>
56 1.1 elric #include <dev/cgdvar.h>
57 1.1 elric
58 1.88 hannken #include <miscfs/specfs/specdev.h> /* for v_rdev */
59 1.88 hannken
60 1.102 christos #include "ioconf.h"
61 1.102 christos
62 1.112 alnsn struct selftest_params {
63 1.112 alnsn const char *alg;
64 1.112 alnsn int blocksize; /* number of bytes */
65 1.112 alnsn int secsize;
66 1.112 alnsn daddr_t blkno;
67 1.112 alnsn int keylen; /* number of bits */
68 1.112 alnsn int txtlen; /* number of bytes */
69 1.112 alnsn const uint8_t *key;
70 1.112 alnsn const uint8_t *ptxt;
71 1.112 alnsn const uint8_t *ctxt;
72 1.112 alnsn };
73 1.112 alnsn
74 1.1 elric /* Entry Point Functions */
75 1.1 elric
76 1.18 thorpej static dev_type_open(cgdopen);
77 1.18 thorpej static dev_type_close(cgdclose);
78 1.18 thorpej static dev_type_read(cgdread);
79 1.18 thorpej static dev_type_write(cgdwrite);
80 1.18 thorpej static dev_type_ioctl(cgdioctl);
81 1.18 thorpej static dev_type_strategy(cgdstrategy);
82 1.18 thorpej static dev_type_dump(cgddump);
83 1.18 thorpej static dev_type_size(cgdsize);
84 1.1 elric
85 1.1 elric const struct bdevsw cgd_bdevsw = {
86 1.114.4.1 pgoyette DEVSW_MODULE_INIT
87 1.84 dholland .d_open = cgdopen,
88 1.84 dholland .d_close = cgdclose,
89 1.84 dholland .d_strategy = cgdstrategy,
90 1.84 dholland .d_ioctl = cgdioctl,
91 1.84 dholland .d_dump = cgddump,
92 1.84 dholland .d_psize = cgdsize,
93 1.89 dholland .d_discard = nodiscard,
94 1.84 dholland .d_flag = D_DISK
95 1.1 elric };
96 1.1 elric
97 1.1 elric const struct cdevsw cgd_cdevsw = {
98 1.114.4.1 pgoyette DEVSW_MODULE_INIT
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.84 dholland .d_flag = D_DISK
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.114.4.1 pgoyette static struct cgd_softc *cgd_spawn(int, device_t *);
212 1.65 dyoung static int cgd_destroy(device_t);
213 1.65 dyoung
214 1.1 elric /* Internal Functions */
215 1.1 elric
216 1.99 mlelstv static int cgd_diskstart(device_t, struct buf *);
217 1.1 elric static void cgdiodone(struct buf *);
218 1.108 riastrad static int cgd_dumpblocks(device_t, void *, daddr_t, int);
219 1.1 elric
220 1.32 christos static int cgd_ioctl_set(struct cgd_softc *, void *, struct lwp *);
221 1.65 dyoung static int cgd_ioctl_clr(struct cgd_softc *, struct lwp *);
222 1.78 christos static int cgd_ioctl_get(dev_t, void *, struct lwp *);
223 1.27 drochner static int cgdinit(struct cgd_softc *, const char *, struct vnode *,
224 1.32 christos struct lwp *);
225 1.44 christos static void cgd_cipher(struct cgd_softc *, void *, void *,
226 1.1 elric size_t, daddr_t, size_t, int);
227 1.1 elric
228 1.29 yamt static struct dkdriver cgddkdriver = {
229 1.98 mlelstv .d_minphys = minphys,
230 1.98 mlelstv .d_open = cgdopen,
231 1.98 mlelstv .d_close = cgdclose,
232 1.98 mlelstv .d_strategy = cgdstrategy,
233 1.98 mlelstv .d_iosize = NULL,
234 1.99 mlelstv .d_diskstart = cgd_diskstart,
235 1.108 riastrad .d_dumpblocks = cgd_dumpblocks,
236 1.98 mlelstv .d_lastclose = NULL
237 1.29 yamt };
238 1.29 yamt
239 1.65 dyoung CFATTACH_DECL3_NEW(cgd, sizeof(struct cgd_softc),
240 1.65 dyoung cgd_match, cgd_attach, cgd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
241 1.65 dyoung extern struct cfdriver cgd_cd;
242 1.65 dyoung
243 1.1 elric /* DIAGNOSTIC and DEBUG definitions */
244 1.1 elric
245 1.1 elric #if defined(CGDDEBUG) && !defined(DEBUG)
246 1.1 elric #define DEBUG
247 1.1 elric #endif
248 1.1 elric
249 1.1 elric #ifdef DEBUG
250 1.1 elric int cgddebug = 0;
251 1.1 elric
252 1.1 elric #define CGDB_FOLLOW 0x1
253 1.1 elric #define CGDB_IO 0x2
254 1.1 elric #define CGDB_CRYPTO 0x4
255 1.1 elric
256 1.1 elric #define IFDEBUG(x,y) if (cgddebug & (x)) y
257 1.1 elric #define DPRINTF(x,y) IFDEBUG(x, printf y)
258 1.1 elric #define DPRINTF_FOLLOW(y) DPRINTF(CGDB_FOLLOW, y)
259 1.1 elric
260 1.26 drochner static void hexprint(const char *, void *, int);
261 1.1 elric
262 1.1 elric #else
263 1.1 elric #define IFDEBUG(x,y)
264 1.1 elric #define DPRINTF(x,y)
265 1.1 elric #define DPRINTF_FOLLOW(y)
266 1.1 elric #endif
267 1.1 elric
268 1.1 elric #ifdef DIAGNOSTIC
269 1.22 perry #define DIAGPANIC(x) panic x
270 1.1 elric #define DIAGCONDPANIC(x,y) if (x) panic y
271 1.1 elric #else
272 1.1 elric #define DIAGPANIC(x)
273 1.1 elric #define DIAGCONDPANIC(x,y)
274 1.1 elric #endif
275 1.1 elric
276 1.1 elric /* Global variables */
277 1.1 elric
278 1.1 elric /* Utility Functions */
279 1.1 elric
280 1.1 elric #define CGDUNIT(x) DISKUNIT(x)
281 1.114.4.1 pgoyette #define GETCGD_SOFTC(_cs, x, _dv) \
282 1.114.4.1 pgoyette if (((_cs) = getcgd_softc(x, &_dv)) == NULL) { \
283 1.114.4.1 pgoyette return ENXIO; \
284 1.114.4.1 pgoyette }
285 1.1 elric
286 1.65 dyoung /* The code */
287 1.65 dyoung
288 1.114.4.1 pgoyette /*
289 1.114.4.1 pgoyette * Lookup the device and return it's softc. If the device doesn't
290 1.114.4.1 pgoyette * exist, spawn it.
291 1.114.4.1 pgoyette *
292 1.114.4.1 pgoyette * In either case, the device is "acquired", and must be "released"
293 1.114.4.1 pgoyette * by the caller after it is finished with the softc.
294 1.114.4.1 pgoyette */
295 1.1 elric static struct cgd_softc *
296 1.114.4.1 pgoyette getcgd_softc(dev_t dev, device_t *self)
297 1.1 elric {
298 1.1 elric int unit = CGDUNIT(dev);
299 1.65 dyoung struct cgd_softc *sc;
300 1.1 elric
301 1.56 cegger DPRINTF_FOLLOW(("getcgd_softc(0x%"PRIx64"): unit = %d\n", dev, unit));
302 1.65 dyoung
303 1.114.4.1 pgoyette *self = device_lookup_acquire(&cgd_cd, unit);
304 1.114.4.1 pgoyette
305 1.114.4.1 pgoyette if (*self == NULL) {
306 1.114.4.1 pgoyette sc = cgd_spawn(unit, self);
307 1.114.4.1 pgoyette } else {
308 1.114.4.1 pgoyette sc = device_private(*self);
309 1.114.4.1 pgoyette }
310 1.114.4.1 pgoyette
311 1.65 dyoung return sc;
312 1.1 elric }
313 1.1 elric
314 1.65 dyoung static int
315 1.65 dyoung cgd_match(device_t self, cfdata_t cfdata, void *aux)
316 1.65 dyoung {
317 1.65 dyoung
318 1.65 dyoung return 1;
319 1.65 dyoung }
320 1.1 elric
321 1.1 elric static void
322 1.65 dyoung cgd_attach(device_t parent, device_t self, void *aux)
323 1.1 elric {
324 1.114.4.1 pgoyette struct cgd_softc *sc;
325 1.114.4.1 pgoyette
326 1.114.4.1 pgoyette sc = device_private(self);
327 1.1 elric
328 1.85 skrll mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO);
329 1.98 mlelstv dk_init(&sc->sc_dksc, self, DKTYPE_CGD);
330 1.65 dyoung disk_init(&sc->sc_dksc.sc_dkdev, sc->sc_dksc.sc_xname, &cgddkdriver);
331 1.70 joerg
332 1.98 mlelstv if (!pmf_device_register(self, NULL, NULL))
333 1.107 msaitoh aprint_error_dev(self,
334 1.107 msaitoh "unable to register power management hooks\n");
335 1.65 dyoung }
336 1.65 dyoung
337 1.65 dyoung
338 1.114.4.1 pgoyette /*
339 1.114.4.4 pgoyette * The caller must hold a reference to the device's localcount.
340 1.114.4.1 pgoyette */
341 1.65 dyoung static int
342 1.65 dyoung cgd_detach(device_t self, int flags)
343 1.65 dyoung {
344 1.67 dyoung int ret;
345 1.67 dyoung const int pmask = 1 << RAW_PART;
346 1.65 dyoung struct cgd_softc *sc = device_private(self);
347 1.67 dyoung struct dk_softc *dksc = &sc->sc_dksc;
348 1.67 dyoung
349 1.67 dyoung if (DK_BUSY(dksc, pmask))
350 1.67 dyoung return EBUSY;
351 1.65 dyoung
352 1.98 mlelstv if (DK_ATTACHED(dksc) &&
353 1.67 dyoung (ret = cgd_ioctl_clr(sc, curlwp)) != 0)
354 1.67 dyoung return ret;
355 1.65 dyoung
356 1.67 dyoung disk_destroy(&dksc->sc_dkdev);
357 1.86 christos mutex_destroy(&sc->sc_lock);
358 1.65 dyoung
359 1.67 dyoung return 0;
360 1.1 elric }
361 1.1 elric
362 1.1 elric void
363 1.1 elric cgdattach(int num)
364 1.1 elric {
365 1.65 dyoung int error;
366 1.65 dyoung
367 1.65 dyoung error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
368 1.65 dyoung if (error != 0)
369 1.65 dyoung aprint_error("%s: unable to register cfattach\n",
370 1.65 dyoung cgd_cd.cd_name);
371 1.65 dyoung }
372 1.65 dyoung
373 1.65 dyoung static struct cgd_softc *
374 1.114.4.1 pgoyette cgd_spawn(int unit, device_t *self)
375 1.65 dyoung {
376 1.65 dyoung cfdata_t cf;
377 1.114.4.1 pgoyette struct cgd_softc *sc;
378 1.65 dyoung
379 1.65 dyoung cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
380 1.65 dyoung cf->cf_name = cgd_cd.cd_name;
381 1.65 dyoung cf->cf_atname = cgd_cd.cd_name;
382 1.65 dyoung cf->cf_unit = unit;
383 1.65 dyoung cf->cf_fstate = FSTATE_STAR;
384 1.65 dyoung
385 1.114.4.1 pgoyette if (config_attach_pseudo(cf) == NULL)
386 1.114.4.1 pgoyette return NULL;
387 1.114.4.1 pgoyette
388 1.114.4.2 pgoyette if ((*self = device_lookup_acquire(&cgd_cd, unit)) == NULL)
389 1.114.4.1 pgoyette return NULL;
390 1.114.4.1 pgoyette else {
391 1.114.4.1 pgoyette /*
392 1.114.4.1 pgoyette * Note that we return while still holding a reference
393 1.114.4.1 pgoyette * to the device!
394 1.114.4.1 pgoyette */
395 1.114.4.1 pgoyette sc = device_private(*self);
396 1.114.4.1 pgoyette return sc;
397 1.114.4.1 pgoyette }
398 1.65 dyoung }
399 1.65 dyoung
400 1.65 dyoung static int
401 1.65 dyoung cgd_destroy(device_t dev)
402 1.65 dyoung {
403 1.65 dyoung int error;
404 1.65 dyoung cfdata_t cf;
405 1.1 elric
406 1.65 dyoung cf = device_cfdata(dev);
407 1.114.4.4 pgoyette error = config_detach_release(dev, DETACH_QUIET);
408 1.114.4.1 pgoyette if (error == 0)
409 1.114.4.1 pgoyette free(cf, M_DEVBUF);
410 1.114.4.1 pgoyette
411 1.114.4.1 pgoyette return error;
412 1.1 elric }
413 1.1 elric
414 1.18 thorpej static int
415 1.32 christos cgdopen(dev_t dev, int flags, int fmt, struct lwp *l)
416 1.1 elric {
417 1.114.4.1 pgoyette device_t self;
418 1.114.4.1 pgoyette int error;
419 1.1 elric struct cgd_softc *cs;
420 1.1 elric
421 1.56 cegger DPRINTF_FOLLOW(("cgdopen(0x%"PRIx64", %d)\n", dev, flags));
422 1.114.4.1 pgoyette GETCGD_SOFTC(cs, dev, self);
423 1.114.4.1 pgoyette error = dk_open(&cs->sc_dksc, dev, flags, fmt, l);
424 1.114.4.1 pgoyette device_release(self);
425 1.114.4.1 pgoyette return error;
426 1.1 elric }
427 1.1 elric
428 1.18 thorpej static int
429 1.32 christos cgdclose(dev_t dev, int flags, int fmt, struct lwp *l)
430 1.1 elric {
431 1.65 dyoung int error;
432 1.114.4.1 pgoyette device_t self;
433 1.1 elric struct cgd_softc *cs;
434 1.65 dyoung struct dk_softc *dksc;
435 1.1 elric
436 1.56 cegger DPRINTF_FOLLOW(("cgdclose(0x%"PRIx64", %d)\n", dev, flags));
437 1.114.4.1 pgoyette GETCGD_SOFTC(cs, dev, self);
438 1.65 dyoung dksc = &cs->sc_dksc;
439 1.114.4.1 pgoyette if ((error = dk_close(dksc, dev, flags, fmt, l)) != 0) {
440 1.114.4.1 pgoyette device_release(self);
441 1.65 dyoung return error;
442 1.114.4.1 pgoyette }
443 1.65 dyoung
444 1.98 mlelstv if (!DK_ATTACHED(dksc)) {
445 1.77 elric if ((error = cgd_destroy(cs->sc_dksc.sc_dev)) != 0) {
446 1.77 elric aprint_error_dev(dksc->sc_dev,
447 1.65 dyoung "unable to detach instance\n");
448 1.65 dyoung }
449 1.114.4.3 pgoyette return error;
450 1.114.4.2 pgoyette }
451 1.114.4.5 pgoyette
452 1.114.4.5 pgoyette /* Unit is still attached - just return */
453 1.114.4.2 pgoyette device_release(self);
454 1.65 dyoung return 0;
455 1.1 elric }
456 1.1 elric
457 1.18 thorpej static void
458 1.1 elric cgdstrategy(struct buf *bp)
459 1.1 elric {
460 1.114.4.1 pgoyette device_t self;
461 1.114.4.1 pgoyette struct cgd_softc *cs = getcgd_softc(bp->b_dev, &self);
462 1.1 elric
463 1.1 elric DPRINTF_FOLLOW(("cgdstrategy(%p): b_bcount = %ld\n", bp,
464 1.1 elric (long)bp->b_bcount));
465 1.72 riastrad
466 1.111 mlelstv if (!cs) {
467 1.111 mlelstv bp->b_error = ENXIO;
468 1.111 mlelstv goto bail;
469 1.111 mlelstv }
470 1.111 mlelstv
471 1.72 riastrad /*
472 1.111 mlelstv * Reject unaligned writes.
473 1.72 riastrad */
474 1.111 mlelstv if (((uintptr_t)bp->b_data & 3) != 0) {
475 1.72 riastrad bp->b_error = EINVAL;
476 1.111 mlelstv goto bail;
477 1.72 riastrad }
478 1.72 riastrad
479 1.98 mlelstv dk_strategy(&cs->sc_dksc, bp);
480 1.114.4.1 pgoyette device_release(self);
481 1.1 elric return;
482 1.111 mlelstv
483 1.111 mlelstv bail:
484 1.111 mlelstv bp->b_resid = bp->b_bcount;
485 1.111 mlelstv biodone(bp);
486 1.114.4.1 pgoyette if (self)
487 1.114.4.1 pgoyette device_release(self);
488 1.111 mlelstv return;
489 1.1 elric }
490 1.1 elric
491 1.18 thorpej static int
492 1.1 elric cgdsize(dev_t dev)
493 1.1 elric {
494 1.114.4.1 pgoyette int retval;
495 1.114.4.1 pgoyette device_t self;
496 1.114.4.1 pgoyette struct cgd_softc *cs = getcgd_softc(dev, &self);
497 1.1 elric
498 1.56 cegger DPRINTF_FOLLOW(("cgdsize(0x%"PRIx64")\n", dev));
499 1.1 elric if (!cs)
500 1.114.4.1 pgoyette retval = -1;
501 1.114.4.1 pgoyette else
502 1.114.4.1 pgoyette retval = dk_size(&cs->sc_dksc, dev);
503 1.114.4.1 pgoyette
504 1.114.4.1 pgoyette device_release(self);
505 1.114.4.1 pgoyette return retval;
506 1.1 elric }
507 1.1 elric
508 1.16 elric /*
509 1.16 elric * cgd_{get,put}data are functions that deal with getting a buffer
510 1.16 elric * for the new encrypted data. We have a buffer per device so that
511 1.16 elric * we can ensure that we can always have a transaction in flight.
512 1.16 elric * We use this buffer first so that we have one less piece of
513 1.16 elric * malloc'ed data at any given point.
514 1.16 elric */
515 1.16 elric
516 1.16 elric static void *
517 1.16 elric cgd_getdata(struct dk_softc *dksc, unsigned long size)
518 1.16 elric {
519 1.77 elric struct cgd_softc *cs = (struct cgd_softc *)dksc;
520 1.44 christos void * data = NULL;
521 1.16 elric
522 1.85 skrll mutex_enter(&cs->sc_lock);
523 1.16 elric if (cs->sc_data_used == 0) {
524 1.16 elric cs->sc_data_used = 1;
525 1.16 elric data = cs->sc_data;
526 1.16 elric }
527 1.85 skrll mutex_exit(&cs->sc_lock);
528 1.16 elric
529 1.16 elric if (data)
530 1.16 elric return data;
531 1.16 elric
532 1.16 elric return malloc(size, M_DEVBUF, M_NOWAIT);
533 1.16 elric }
534 1.16 elric
535 1.1 elric static void
536 1.44 christos cgd_putdata(struct dk_softc *dksc, void *data)
537 1.16 elric {
538 1.77 elric struct cgd_softc *cs = (struct cgd_softc *)dksc;
539 1.16 elric
540 1.16 elric if (data == cs->sc_data) {
541 1.85 skrll mutex_enter(&cs->sc_lock);
542 1.16 elric cs->sc_data_used = 0;
543 1.85 skrll mutex_exit(&cs->sc_lock);
544 1.16 elric } else {
545 1.16 elric free(data, M_DEVBUF);
546 1.16 elric }
547 1.16 elric }
548 1.16 elric
549 1.99 mlelstv static int
550 1.99 mlelstv cgd_diskstart(device_t dev, struct buf *bp)
551 1.1 elric {
552 1.98 mlelstv struct cgd_softc *cs = device_private(dev);
553 1.98 mlelstv struct dk_softc *dksc = &cs->sc_dksc;
554 1.105 mlelstv struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
555 1.99 mlelstv struct buf *nbp;
556 1.44 christos void * addr;
557 1.44 christos void * newaddr;
558 1.1 elric daddr_t bn;
559 1.49 ad struct vnode *vp;
560 1.1 elric
561 1.99 mlelstv DPRINTF_FOLLOW(("cgd_diskstart(%p, %p)\n", dksc, bp));
562 1.1 elric
563 1.99 mlelstv bn = bp->b_rawblkno;
564 1.22 perry
565 1.99 mlelstv /*
566 1.99 mlelstv * We attempt to allocate all of our resources up front, so that
567 1.99 mlelstv * we can fail quickly if they are unavailable.
568 1.99 mlelstv */
569 1.99 mlelstv nbp = getiobuf(cs->sc_tvn, false);
570 1.99 mlelstv if (nbp == NULL)
571 1.99 mlelstv return EAGAIN;
572 1.16 elric
573 1.99 mlelstv /*
574 1.99 mlelstv * If we are writing, then we need to encrypt the outgoing
575 1.99 mlelstv * block into a new block of memory.
576 1.99 mlelstv */
577 1.99 mlelstv newaddr = addr = bp->b_data;
578 1.99 mlelstv if ((bp->b_flags & B_READ) == 0) {
579 1.99 mlelstv newaddr = cgd_getdata(dksc, bp->b_bcount);
580 1.99 mlelstv if (!newaddr) {
581 1.99 mlelstv putiobuf(nbp);
582 1.99 mlelstv return EAGAIN;
583 1.16 elric }
584 1.99 mlelstv cgd_cipher(cs, newaddr, addr, bp->b_bcount, bn,
585 1.105 mlelstv dg->dg_secsize, CGD_CIPHER_ENCRYPT);
586 1.99 mlelstv }
587 1.1 elric
588 1.99 mlelstv nbp->b_data = newaddr;
589 1.99 mlelstv nbp->b_flags = bp->b_flags;
590 1.99 mlelstv nbp->b_oflags = bp->b_oflags;
591 1.99 mlelstv nbp->b_cflags = bp->b_cflags;
592 1.99 mlelstv nbp->b_iodone = cgdiodone;
593 1.99 mlelstv nbp->b_proc = bp->b_proc;
594 1.105 mlelstv nbp->b_blkno = btodb(bn * dg->dg_secsize);
595 1.99 mlelstv nbp->b_bcount = bp->b_bcount;
596 1.99 mlelstv nbp->b_private = bp;
597 1.99 mlelstv
598 1.99 mlelstv BIO_COPYPRIO(nbp, bp);
599 1.99 mlelstv
600 1.99 mlelstv if ((nbp->b_flags & B_READ) == 0) {
601 1.99 mlelstv vp = nbp->b_vp;
602 1.99 mlelstv mutex_enter(vp->v_interlock);
603 1.99 mlelstv vp->v_numoutput++;
604 1.99 mlelstv mutex_exit(vp->v_interlock);
605 1.17 dbj }
606 1.99 mlelstv VOP_STRATEGY(cs->sc_tvn, nbp);
607 1.99 mlelstv
608 1.99 mlelstv return 0;
609 1.1 elric }
610 1.1 elric
611 1.18 thorpej static void
612 1.17 dbj cgdiodone(struct buf *nbp)
613 1.1 elric {
614 1.114.4.1 pgoyette device_t self;
615 1.17 dbj struct buf *obp = nbp->b_private;
616 1.114.4.1 pgoyette struct cgd_softc *cs = getcgd_softc(obp->b_dev, &self);
617 1.1 elric struct dk_softc *dksc = &cs->sc_dksc;
618 1.105 mlelstv struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
619 1.105 mlelstv daddr_t bn;
620 1.22 perry
621 1.17 dbj KDASSERT(cs);
622 1.1 elric
623 1.17 dbj DPRINTF_FOLLOW(("cgdiodone(%p)\n", nbp));
624 1.20 yamt DPRINTF(CGDB_IO, ("cgdiodone: bp %p bcount %d resid %d\n",
625 1.1 elric obp, obp->b_bcount, obp->b_resid));
626 1.107 msaitoh DPRINTF(CGDB_IO, (" dev 0x%"PRIx64", nbp %p bn %" PRId64
627 1.107 msaitoh " addr %p bcnt %d\n", nbp->b_dev, nbp, nbp->b_blkno, nbp->b_data,
628 1.107 msaitoh nbp->b_bcount));
629 1.46 ad if (nbp->b_error != 0) {
630 1.46 ad obp->b_error = nbp->b_error;
631 1.62 christos DPRINTF(CGDB_IO, ("%s: error %d\n", dksc->sc_xname,
632 1.62 christos obp->b_error));
633 1.1 elric }
634 1.1 elric
635 1.16 elric /* Perform the decryption if we are reading.
636 1.1 elric *
637 1.1 elric * Note: use the blocknumber from nbp, since it is what
638 1.1 elric * we used to encrypt the blocks.
639 1.1 elric */
640 1.1 elric
641 1.105 mlelstv if (nbp->b_flags & B_READ) {
642 1.105 mlelstv bn = dbtob(nbp->b_blkno) / dg->dg_secsize;
643 1.1 elric cgd_cipher(cs, obp->b_data, obp->b_data, obp->b_bcount,
644 1.105 mlelstv bn, dg->dg_secsize, CGD_CIPHER_DECRYPT);
645 1.105 mlelstv }
646 1.1 elric
647 1.16 elric /* If we allocated memory, free it now... */
648 1.1 elric if (nbp->b_data != obp->b_data)
649 1.16 elric cgd_putdata(dksc, nbp->b_data);
650 1.1 elric
651 1.33 yamt putiobuf(nbp);
652 1.1 elric
653 1.100 mlelstv /* Request is complete for whatever reason */
654 1.100 mlelstv obp->b_resid = 0;
655 1.100 mlelstv if (obp->b_error != 0)
656 1.100 mlelstv obp->b_resid = obp->b_bcount;
657 1.100 mlelstv
658 1.99 mlelstv dk_done(dksc, obp);
659 1.114.4.1 pgoyette device_release(self);
660 1.114.4.1 pgoyette
661 1.101 mlelstv dk_start(dksc, NULL);
662 1.1 elric }
663 1.1 elric
664 1.108 riastrad static int
665 1.108 riastrad cgd_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk)
666 1.108 riastrad {
667 1.108 riastrad struct cgd_softc *sc = device_private(dev);
668 1.108 riastrad struct dk_softc *dksc = &sc->sc_dksc;
669 1.108 riastrad struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
670 1.108 riastrad size_t nbytes, blksize;
671 1.108 riastrad void *buf;
672 1.108 riastrad int error;
673 1.108 riastrad
674 1.108 riastrad /*
675 1.108 riastrad * dk_dump gives us units of disklabel sectors. Everything
676 1.108 riastrad * else in cgd uses units of diskgeom sectors. These had
677 1.108 riastrad * better agree; otherwise we need to figure out how to convert
678 1.108 riastrad * between them.
679 1.108 riastrad */
680 1.108 riastrad KASSERTMSG((dg->dg_secsize == dksc->sc_dkdev.dk_label->d_secsize),
681 1.108 riastrad "diskgeom secsize %"PRIu32" != disklabel secsize %"PRIu32,
682 1.108 riastrad dg->dg_secsize, dksc->sc_dkdev.dk_label->d_secsize);
683 1.108 riastrad blksize = dg->dg_secsize;
684 1.108 riastrad
685 1.108 riastrad /*
686 1.108 riastrad * Compute the number of bytes in this request, which dk_dump
687 1.108 riastrad * has `helpfully' converted to a number of blocks for us.
688 1.108 riastrad */
689 1.108 riastrad nbytes = nblk*blksize;
690 1.108 riastrad
691 1.108 riastrad /* Try to acquire a buffer to store the ciphertext. */
692 1.108 riastrad buf = cgd_getdata(dksc, nbytes);
693 1.108 riastrad if (buf == NULL)
694 1.108 riastrad /* Out of memory: give up. */
695 1.108 riastrad return ENOMEM;
696 1.108 riastrad
697 1.108 riastrad /* Encrypt the caller's data into the temporary buffer. */
698 1.108 riastrad cgd_cipher(sc, buf, va, nbytes, blkno, blksize, CGD_CIPHER_ENCRYPT);
699 1.108 riastrad
700 1.108 riastrad /* Pass it on to the underlying disk device. */
701 1.108 riastrad error = bdev_dump(sc->sc_tdev, blkno, buf, nbytes);
702 1.108 riastrad
703 1.108 riastrad /* Release the buffer. */
704 1.108 riastrad cgd_putdata(dksc, buf);
705 1.108 riastrad
706 1.108 riastrad /* Return any error from the underlying disk device. */
707 1.108 riastrad return error;
708 1.108 riastrad }
709 1.108 riastrad
710 1.1 elric /* XXX: we should probably put these into dksubr.c, mostly */
711 1.18 thorpej static int
712 1.40 christos cgdread(dev_t dev, struct uio *uio, int flags)
713 1.1 elric {
714 1.114.4.1 pgoyette device_t self;
715 1.114.4.1 pgoyette int error;
716 1.1 elric struct cgd_softc *cs;
717 1.1 elric struct dk_softc *dksc;
718 1.1 elric
719 1.56 cegger DPRINTF_FOLLOW(("cgdread(0x%llx, %p, %d)\n",
720 1.56 cegger (unsigned long long)dev, uio, flags));
721 1.114.4.1 pgoyette GETCGD_SOFTC(cs, dev, self);
722 1.1 elric dksc = &cs->sc_dksc;
723 1.114.4.1 pgoyette if (!DK_ATTACHED(dksc)) {
724 1.114.4.1 pgoyette device_release(self);
725 1.1 elric return ENXIO;
726 1.114.4.1 pgoyette }
727 1.114.4.1 pgoyette error = physio(cgdstrategy, NULL, dev, B_READ, minphys, uio);
728 1.114.4.1 pgoyette device_release(self);
729 1.114.4.1 pgoyette return error;
730 1.1 elric }
731 1.1 elric
732 1.1 elric /* XXX: we should probably put these into dksubr.c, mostly */
733 1.18 thorpej static int
734 1.40 christos cgdwrite(dev_t dev, struct uio *uio, int flags)
735 1.1 elric {
736 1.114.4.1 pgoyette device_t self;
737 1.114.4.1 pgoyette int error;
738 1.1 elric struct cgd_softc *cs;
739 1.1 elric struct dk_softc *dksc;
740 1.1 elric
741 1.56 cegger DPRINTF_FOLLOW(("cgdwrite(0x%"PRIx64", %p, %d)\n", dev, uio, flags));
742 1.114.4.1 pgoyette GETCGD_SOFTC(cs, dev, self);
743 1.1 elric dksc = &cs->sc_dksc;
744 1.114.4.1 pgoyette if (!DK_ATTACHED(dksc)) {
745 1.114.4.1 pgoyette device_release(self);
746 1.1 elric return ENXIO;
747 1.114.4.1 pgoyette }
748 1.114.4.1 pgoyette error = physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio);
749 1.114.4.1 pgoyette device_release(self);
750 1.114.4.1 pgoyette return error;
751 1.1 elric }
752 1.1 elric
753 1.18 thorpej static int
754 1.44 christos cgdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
755 1.1 elric {
756 1.114.4.1 pgoyette device_t self;
757 1.1 elric struct cgd_softc *cs;
758 1.1 elric struct dk_softc *dksc;
759 1.1 elric int part = DISKPART(dev);
760 1.1 elric int pmask = 1 << part;
761 1.114.4.1 pgoyette int error = 0;
762 1.1 elric
763 1.56 cegger DPRINTF_FOLLOW(("cgdioctl(0x%"PRIx64", %ld, %p, %d, %p)\n",
764 1.32 christos dev, cmd, data, flag, l));
765 1.78 christos
766 1.1 elric switch (cmd) {
767 1.93 christos case CGDIOCGET:
768 1.93 christos return cgd_ioctl_get(dev, data, l);
769 1.1 elric case CGDIOCSET:
770 1.1 elric case CGDIOCCLR:
771 1.1 elric if ((flag & FWRITE) == 0)
772 1.1 elric return EBADF;
773 1.78 christos /* FALLTHROUGH */
774 1.78 christos default:
775 1.114.4.1 pgoyette GETCGD_SOFTC(cs, dev, self);
776 1.78 christos dksc = &cs->sc_dksc;
777 1.78 christos break;
778 1.1 elric }
779 1.1 elric
780 1.1 elric switch (cmd) {
781 1.1 elric case CGDIOCSET:
782 1.98 mlelstv if (DK_ATTACHED(dksc))
783 1.114.4.1 pgoyette error = EBUSY;
784 1.114.4.1 pgoyette else
785 1.114.4.1 pgoyette error = cgd_ioctl_set(cs, data, l);
786 1.114.4.1 pgoyette break;
787 1.1 elric case CGDIOCCLR:
788 1.65 dyoung if (DK_BUSY(&cs->sc_dksc, pmask))
789 1.114.4.2 pgoyette error = EBUSY;
790 1.114.4.2 pgoyette else
791 1.114.4.2 pgoyette error = cgd_ioctl_clr(cs, l);
792 1.114.4.2 pgoyette break;
793 1.114 jdolecek case DIOCGCACHE:
794 1.57 apb case DIOCCACHESYNC:
795 1.114 jdolecek if (!DK_ATTACHED(dksc))
796 1.114 jdolecek return ENOENT;
797 1.57 apb /*
798 1.57 apb * We pass this call down to the underlying disk.
799 1.57 apb */
800 1.114.4.1 pgoyette else
801 1.114.4.1 pgoyette error = VOP_IOCTL(cs->sc_tvn, cmd, data, flag,
802 1.114.4.1 pgoyette l->l_cred);
803 1.114.4.1 pgoyette break;
804 1.103 christos case DIOCGSTRATEGY:
805 1.103 christos case DIOCSSTRATEGY:
806 1.114.4.1 pgoyette if (!DK_ATTACHED(dksc)) {
807 1.114.4.1 pgoyette error = ENOENT;
808 1.114.4.1 pgoyette break;
809 1.114.4.1 pgoyette }
810 1.103 christos /*FALLTHROUGH*/
811 1.1 elric default:
812 1.114.4.1 pgoyette error = dk_ioctl(dksc, dev, cmd, data, flag, l);
813 1.114.4.1 pgoyette break;
814 1.93 christos case CGDIOCGET:
815 1.93 christos KASSERT(0);
816 1.114.4.1 pgoyette error = EINVAL;
817 1.114.4.1 pgoyette break;
818 1.1 elric }
819 1.114.4.1 pgoyette device_release(self);
820 1.114.4.1 pgoyette return error;
821 1.1 elric }
822 1.1 elric
823 1.18 thorpej static int
824 1.44 christos cgddump(dev_t dev, daddr_t blkno, void *va, size_t size)
825 1.1 elric {
826 1.114.4.1 pgoyette device_t self;
827 1.114.4.1 pgoyette int error;
828 1.1 elric struct cgd_softc *cs;
829 1.1 elric
830 1.56 cegger DPRINTF_FOLLOW(("cgddump(0x%"PRIx64", %" PRId64 ", %p, %lu)\n",
831 1.56 cegger dev, blkno, va, (unsigned long)size));
832 1.114.4.1 pgoyette GETCGD_SOFTC(cs, dev, self);
833 1.114.4.1 pgoyette error = dk_dump(&cs->sc_dksc, dev, blkno, va, size);
834 1.114.4.1 pgoyette device_release(self);
835 1.114.4.1 pgoyette return error;
836 1.1 elric }
837 1.1 elric
838 1.1 elric /*
839 1.1 elric * XXXrcd:
840 1.1 elric * for now we hardcode the maximum key length.
841 1.1 elric */
842 1.1 elric #define MAX_KEYSIZE 1024
843 1.1 elric
844 1.53 christos static const struct {
845 1.53 christos const char *n;
846 1.53 christos int v;
847 1.53 christos int d;
848 1.53 christos } encblkno[] = {
849 1.53 christos { "encblkno", CGD_CIPHER_CBC_ENCBLKNO8, 1 },
850 1.53 christos { "encblkno8", CGD_CIPHER_CBC_ENCBLKNO8, 1 },
851 1.53 christos { "encblkno1", CGD_CIPHER_CBC_ENCBLKNO1, 8 },
852 1.53 christos };
853 1.53 christos
854 1.1 elric /* ARGSUSED */
855 1.1 elric static int
856 1.32 christos cgd_ioctl_set(struct cgd_softc *cs, void *data, struct lwp *l)
857 1.1 elric {
858 1.1 elric struct cgd_ioctl *ci = data;
859 1.1 elric struct vnode *vp;
860 1.1 elric int ret;
861 1.53 christos size_t i;
862 1.43 cbiere size_t keybytes; /* key length in bytes */
863 1.27 drochner const char *cp;
864 1.71 dholland struct pathbuf *pb;
865 1.36 christos char *inbuf;
866 1.80 christos struct dk_softc *dksc = &cs->sc_dksc;
867 1.1 elric
868 1.1 elric cp = ci->ci_disk;
869 1.71 dholland
870 1.71 dholland ret = pathbuf_copyin(ci->ci_disk, &pb);
871 1.71 dholland if (ret != 0) {
872 1.71 dholland return ret;
873 1.71 dholland }
874 1.71 dholland ret = dk_lookup(pb, l, &vp);
875 1.71 dholland pathbuf_destroy(pb);
876 1.71 dholland if (ret != 0) {
877 1.1 elric return ret;
878 1.71 dholland }
879 1.1 elric
880 1.36 christos inbuf = malloc(MAX_KEYSIZE, M_TEMP, M_WAITOK);
881 1.36 christos
882 1.32 christos if ((ret = cgdinit(cs, cp, vp, l)) != 0)
883 1.1 elric goto bail;
884 1.1 elric
885 1.36 christos (void)memset(inbuf, 0, MAX_KEYSIZE);
886 1.1 elric ret = copyinstr(ci->ci_alg, inbuf, 256, NULL);
887 1.1 elric if (ret)
888 1.1 elric goto bail;
889 1.1 elric cs->sc_cfuncs = cryptfuncs_find(inbuf);
890 1.1 elric if (!cs->sc_cfuncs) {
891 1.1 elric ret = EINVAL;
892 1.1 elric goto bail;
893 1.1 elric }
894 1.1 elric
895 1.43 cbiere (void)memset(inbuf, 0, MAX_KEYSIZE);
896 1.36 christos ret = copyinstr(ci->ci_ivmethod, inbuf, MAX_KEYSIZE, NULL);
897 1.1 elric if (ret)
898 1.1 elric goto bail;
899 1.53 christos
900 1.53 christos for (i = 0; i < __arraycount(encblkno); i++)
901 1.53 christos if (strcmp(encblkno[i].n, inbuf) == 0)
902 1.53 christos break;
903 1.53 christos
904 1.53 christos if (i == __arraycount(encblkno)) {
905 1.1 elric ret = EINVAL;
906 1.1 elric goto bail;
907 1.1 elric }
908 1.1 elric
909 1.15 dan keybytes = ci->ci_keylen / 8 + 1;
910 1.15 dan if (keybytes > MAX_KEYSIZE) {
911 1.1 elric ret = EINVAL;
912 1.1 elric goto bail;
913 1.1 elric }
914 1.53 christos
915 1.36 christos (void)memset(inbuf, 0, MAX_KEYSIZE);
916 1.15 dan ret = copyin(ci->ci_key, inbuf, keybytes);
917 1.1 elric if (ret)
918 1.1 elric goto bail;
919 1.1 elric
920 1.1 elric cs->sc_cdata.cf_blocksize = ci->ci_blocksize;
921 1.53 christos cs->sc_cdata.cf_mode = encblkno[i].v;
922 1.78 christos cs->sc_cdata.cf_keylen = ci->ci_keylen;
923 1.1 elric cs->sc_cdata.cf_priv = cs->sc_cfuncs->cf_init(ci->ci_keylen, inbuf,
924 1.1 elric &cs->sc_cdata.cf_blocksize);
925 1.62 christos if (cs->sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE) {
926 1.62 christos log(LOG_WARNING, "cgd: Disallowed cipher with blocksize %zu > %u\n",
927 1.63 christos cs->sc_cdata.cf_blocksize, CGD_MAXBLOCKSIZE);
928 1.62 christos cs->sc_cdata.cf_priv = NULL;
929 1.62 christos }
930 1.78 christos
931 1.53 christos /*
932 1.53 christos * The blocksize is supposed to be in bytes. Unfortunately originally
933 1.53 christos * it was expressed in bits. For compatibility we maintain encblkno
934 1.53 christos * and encblkno8.
935 1.53 christos */
936 1.53 christos cs->sc_cdata.cf_blocksize /= encblkno[i].d;
937 1.97 riastrad (void)explicit_memset(inbuf, 0, MAX_KEYSIZE);
938 1.1 elric if (!cs->sc_cdata.cf_priv) {
939 1.1 elric ret = EINVAL; /* XXX is this the right error? */
940 1.1 elric goto bail;
941 1.1 elric }
942 1.36 christos free(inbuf, M_TEMP);
943 1.1 elric
944 1.80 christos bufq_alloc(&dksc->sc_bufq, "fcfs", 0);
945 1.16 elric
946 1.16 elric cs->sc_data = malloc(MAXPHYS, M_DEVBUF, M_WAITOK);
947 1.16 elric cs->sc_data_used = 0;
948 1.16 elric
949 1.98 mlelstv /* Attach the disk. */
950 1.98 mlelstv dk_attach(dksc);
951 1.98 mlelstv disk_attach(&dksc->sc_dkdev);
952 1.1 elric
953 1.80 christos disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
954 1.77 elric
955 1.29 yamt /* Discover wedges on this disk. */
956 1.80 christos dkwedge_discover(&dksc->sc_dkdev);
957 1.29 yamt
958 1.1 elric return 0;
959 1.1 elric
960 1.1 elric bail:
961 1.36 christos free(inbuf, M_TEMP);
962 1.51 ad (void)vn_close(vp, FREAD|FWRITE, l->l_cred);
963 1.1 elric return ret;
964 1.1 elric }
965 1.1 elric
966 1.1 elric /* ARGSUSED */
967 1.1 elric static int
968 1.65 dyoung cgd_ioctl_clr(struct cgd_softc *cs, struct lwp *l)
969 1.1 elric {
970 1.80 christos struct dk_softc *dksc = &cs->sc_dksc;
971 1.65 dyoung
972 1.98 mlelstv if (!DK_ATTACHED(dksc))
973 1.65 dyoung return ENXIO;
974 1.16 elric
975 1.29 yamt /* Delete all of our wedges. */
976 1.80 christos dkwedge_delall(&dksc->sc_dkdev);
977 1.29 yamt
978 1.16 elric /* Kill off any queued buffers. */
979 1.104 mlelstv dk_drain(dksc);
980 1.80 christos bufq_free(dksc->sc_bufq);
981 1.1 elric
982 1.51 ad (void)vn_close(cs->sc_tvn, FREAD|FWRITE, l->l_cred);
983 1.1 elric cs->sc_cfuncs->cf_destroy(cs->sc_cdata.cf_priv);
984 1.1 elric free(cs->sc_tpath, M_DEVBUF);
985 1.16 elric free(cs->sc_data, M_DEVBUF);
986 1.16 elric cs->sc_data_used = 0;
987 1.98 mlelstv dk_detach(dksc);
988 1.80 christos disk_detach(&dksc->sc_dkdev);
989 1.1 elric
990 1.1 elric return 0;
991 1.1 elric }
992 1.1 elric
993 1.1 elric static int
994 1.78 christos cgd_ioctl_get(dev_t dev, void *data, struct lwp *l)
995 1.78 christos {
996 1.114.4.1 pgoyette device_t self;
997 1.114.4.1 pgoyette struct cgd_softc *cs = getcgd_softc(dev, &self);
998 1.78 christos struct cgd_user *cgu;
999 1.78 christos int unit;
1000 1.80 christos struct dk_softc *dksc = &cs->sc_dksc;
1001 1.78 christos
1002 1.78 christos unit = CGDUNIT(dev);
1003 1.78 christos cgu = (struct cgd_user *)data;
1004 1.78 christos
1005 1.78 christos DPRINTF_FOLLOW(("cgd_ioctl_get(0x%"PRIx64", %d, %p, %p)\n",
1006 1.78 christos dev, unit, data, l));
1007 1.78 christos
1008 1.78 christos if (cgu->cgu_unit == -1)
1009 1.78 christos cgu->cgu_unit = unit;
1010 1.78 christos
1011 1.114.4.1 pgoyette if (cgu->cgu_unit < 0) {
1012 1.114.4.1 pgoyette device_release(self);
1013 1.78 christos return EINVAL; /* XXX: should this be ENXIO? */
1014 1.114.4.1 pgoyette }
1015 1.78 christos
1016 1.114.4.1 pgoyette /*
1017 1.114.4.1 pgoyette * XXX This appears to be redundant, given the initialization
1018 1.114.4.1 pgoyette * XXX when it was declared. Leave it for now, but don't
1019 1.114.4.1 pgoyette * XXX take an extra reference to the device!
1020 1.114.4.1 pgoyette */
1021 1.78 christos cs = device_lookup_private(&cgd_cd, unit);
1022 1.98 mlelstv if (cs == NULL || !DK_ATTACHED(dksc)) {
1023 1.78 christos cgu->cgu_dev = 0;
1024 1.78 christos cgu->cgu_alg[0] = '\0';
1025 1.78 christos cgu->cgu_blocksize = 0;
1026 1.78 christos cgu->cgu_mode = 0;
1027 1.78 christos cgu->cgu_keylen = 0;
1028 1.78 christos }
1029 1.78 christos else {
1030 1.78 christos cgu->cgu_dev = cs->sc_tdev;
1031 1.78 christos strlcpy(cgu->cgu_alg, cs->sc_cfuncs->cf_name,
1032 1.78 christos sizeof(cgu->cgu_alg));
1033 1.78 christos cgu->cgu_blocksize = cs->sc_cdata.cf_blocksize;
1034 1.78 christos cgu->cgu_mode = cs->sc_cdata.cf_mode;
1035 1.78 christos cgu->cgu_keylen = cs->sc_cdata.cf_keylen;
1036 1.78 christos }
1037 1.114.4.1 pgoyette device_release(self);
1038 1.78 christos return 0;
1039 1.78 christos }
1040 1.78 christos
1041 1.78 christos static int
1042 1.27 drochner cgdinit(struct cgd_softc *cs, const char *cpath, struct vnode *vp,
1043 1.32 christos struct lwp *l)
1044 1.1 elric {
1045 1.80 christos struct disk_geom *dg;
1046 1.1 elric int ret;
1047 1.36 christos char *tmppath;
1048 1.76 christos uint64_t psize;
1049 1.76 christos unsigned secsize;
1050 1.80 christos struct dk_softc *dksc = &cs->sc_dksc;
1051 1.1 elric
1052 1.1 elric cs->sc_tvn = vp;
1053 1.36 christos cs->sc_tpath = NULL;
1054 1.1 elric
1055 1.36 christos tmppath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
1056 1.1 elric ret = copyinstr(cpath, tmppath, MAXPATHLEN, &cs->sc_tpathlen);
1057 1.1 elric if (ret)
1058 1.1 elric goto bail;
1059 1.1 elric cs->sc_tpath = malloc(cs->sc_tpathlen, M_DEVBUF, M_WAITOK);
1060 1.1 elric memcpy(cs->sc_tpath, tmppath, cs->sc_tpathlen);
1061 1.1 elric
1062 1.88 hannken cs->sc_tdev = vp->v_rdev;
1063 1.1 elric
1064 1.76 christos if ((ret = getdisksize(vp, &psize, &secsize)) != 0)
1065 1.1 elric goto bail;
1066 1.1 elric
1067 1.76 christos if (psize == 0) {
1068 1.1 elric ret = ENODEV;
1069 1.1 elric goto bail;
1070 1.1 elric }
1071 1.1 elric
1072 1.1 elric /*
1073 1.1 elric * XXX here we should probe the underlying device. If we
1074 1.1 elric * are accessing a partition of type RAW_PART, then
1075 1.1 elric * we should populate our initial geometry with the
1076 1.1 elric * geometry that we discover from the device.
1077 1.1 elric */
1078 1.80 christos dg = &dksc->sc_dkdev.dk_geom;
1079 1.80 christos memset(dg, 0, sizeof(*dg));
1080 1.80 christos dg->dg_secperunit = psize;
1081 1.105 mlelstv dg->dg_secsize = secsize;
1082 1.80 christos dg->dg_ntracks = 1;
1083 1.105 mlelstv dg->dg_nsectors = 1024 * 1024 / dg->dg_secsize;
1084 1.80 christos dg->dg_ncylinders = dg->dg_secperunit / dg->dg_nsectors;
1085 1.1 elric
1086 1.1 elric bail:
1087 1.36 christos free(tmppath, M_TEMP);
1088 1.1 elric if (ret && cs->sc_tpath)
1089 1.1 elric free(cs->sc_tpath, M_DEVBUF);
1090 1.1 elric return ret;
1091 1.1 elric }
1092 1.1 elric
1093 1.1 elric /*
1094 1.1 elric * Our generic cipher entry point. This takes care of the
1095 1.1 elric * IV mode and passes off the work to the specific cipher.
1096 1.1 elric * We implement here the IV method ``encrypted block
1097 1.1 elric * number''.
1098 1.22 perry *
1099 1.1 elric * XXXrcd: for now we rely on our own crypto framework defined
1100 1.1 elric * in dev/cgd_crypto.c. This will change when we
1101 1.1 elric * get a generic kernel crypto framework.
1102 1.1 elric */
1103 1.1 elric
1104 1.1 elric static void
1105 1.25 xtraeme blkno2blkno_buf(char *sbuf, daddr_t blkno)
1106 1.1 elric {
1107 1.1 elric int i;
1108 1.1 elric
1109 1.1 elric /* Set up the blkno in blkno_buf, here we do not care much
1110 1.1 elric * about the final layout of the information as long as we
1111 1.1 elric * can guarantee that each sector will have a different IV
1112 1.1 elric * and that the endianness of the machine will not affect
1113 1.1 elric * the representation that we have chosen.
1114 1.1 elric *
1115 1.1 elric * We choose this representation, because it does not rely
1116 1.1 elric * on the size of buf (which is the blocksize of the cipher),
1117 1.1 elric * but allows daddr_t to grow without breaking existing
1118 1.1 elric * disks.
1119 1.1 elric *
1120 1.1 elric * Note that blkno2blkno_buf does not take a size as input,
1121 1.1 elric * and hence must be called on a pre-zeroed buffer of length
1122 1.1 elric * greater than or equal to sizeof(daddr_t).
1123 1.1 elric */
1124 1.1 elric for (i=0; i < sizeof(daddr_t); i++) {
1125 1.25 xtraeme *sbuf++ = blkno & 0xff;
1126 1.1 elric blkno >>= 8;
1127 1.1 elric }
1128 1.1 elric }
1129 1.1 elric
1130 1.1 elric static void
1131 1.44 christos cgd_cipher(struct cgd_softc *cs, void *dstv, void *srcv,
1132 1.44 christos size_t len, daddr_t blkno, size_t secsize, int dir)
1133 1.1 elric {
1134 1.44 christos char *dst = dstv;
1135 1.112 alnsn char *src = srcv;
1136 1.112 alnsn cfunc_cipher_prep *ciprep = cs->sc_cfuncs->cf_cipher_prep;
1137 1.1 elric cfunc_cipher *cipher = cs->sc_cfuncs->cf_cipher;
1138 1.1 elric struct uio dstuio;
1139 1.1 elric struct uio srcuio;
1140 1.1 elric struct iovec dstiov[2];
1141 1.1 elric struct iovec srciov[2];
1142 1.42 christos size_t blocksize = cs->sc_cdata.cf_blocksize;
1143 1.105 mlelstv size_t todo;
1144 1.112 alnsn char blkno_buf[CGD_MAXBLOCKSIZE], *iv;
1145 1.1 elric
1146 1.1 elric DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir));
1147 1.1 elric
1148 1.22 perry DIAGCONDPANIC(len % blocksize != 0,
1149 1.1 elric ("cgd_cipher: len %% blocksize != 0"));
1150 1.1 elric
1151 1.1 elric /* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */
1152 1.1 elric DIAGCONDPANIC(sizeof(daddr_t) > blocksize,
1153 1.1 elric ("cgd_cipher: sizeof(daddr_t) > blocksize"));
1154 1.1 elric
1155 1.112 alnsn DIAGCONDPANIC(blocksize > CGD_MAXBLOCKSIZE,
1156 1.112 alnsn ("cgd_cipher: blocksize > CGD_MAXBLOCKSIZE"));
1157 1.1 elric
1158 1.1 elric dstuio.uio_iov = dstiov;
1159 1.112 alnsn dstuio.uio_iovcnt = 1;
1160 1.1 elric
1161 1.1 elric srcuio.uio_iov = srciov;
1162 1.112 alnsn srcuio.uio_iovcnt = 1;
1163 1.1 elric
1164 1.105 mlelstv for (; len > 0; len -= todo) {
1165 1.105 mlelstv todo = MIN(len, secsize);
1166 1.105 mlelstv
1167 1.112 alnsn dstiov[0].iov_base = dst;
1168 1.112 alnsn srciov[0].iov_base = src;
1169 1.112 alnsn dstiov[0].iov_len = todo;
1170 1.112 alnsn srciov[0].iov_len = todo;
1171 1.1 elric
1172 1.64 christos memset(blkno_buf, 0x0, blocksize);
1173 1.1 elric blkno2blkno_buf(blkno_buf, blkno);
1174 1.1 elric IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf",
1175 1.64 christos blkno_buf, blocksize));
1176 1.112 alnsn
1177 1.112 alnsn /*
1178 1.112 alnsn * Compute an initial IV. All ciphers
1179 1.112 alnsn * can convert blkno_buf in-place.
1180 1.112 alnsn */
1181 1.112 alnsn iv = blkno_buf;
1182 1.112 alnsn ciprep(cs->sc_cdata.cf_priv, iv, blkno_buf, blocksize, dir);
1183 1.112 alnsn IFDEBUG(CGDB_CRYPTO, hexprint("step 2: iv", iv, blocksize));
1184 1.112 alnsn
1185 1.112 alnsn cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, iv, dir);
1186 1.1 elric
1187 1.105 mlelstv dst += todo;
1188 1.105 mlelstv src += todo;
1189 1.1 elric blkno++;
1190 1.1 elric }
1191 1.1 elric }
1192 1.1 elric
1193 1.1 elric #ifdef DEBUG
1194 1.1 elric static void
1195 1.26 drochner hexprint(const char *start, void *buf, int len)
1196 1.1 elric {
1197 1.1 elric char *c = buf;
1198 1.1 elric
1199 1.1 elric DIAGCONDPANIC(len < 0, ("hexprint: called with len < 0"));
1200 1.1 elric printf("%s: len=%06d 0x", start, len);
1201 1.1 elric while (len--)
1202 1.43 cbiere printf("%02x", (unsigned char) *c++);
1203 1.1 elric }
1204 1.1 elric #endif
1205 1.58 haad
1206 1.112 alnsn static void
1207 1.112 alnsn selftest(void)
1208 1.112 alnsn {
1209 1.112 alnsn struct cgd_softc cs;
1210 1.112 alnsn void *buf;
1211 1.112 alnsn
1212 1.112 alnsn printf("running cgd selftest ");
1213 1.112 alnsn
1214 1.112 alnsn for (size_t i = 0; i < __arraycount(selftests); i++) {
1215 1.112 alnsn const char *alg = selftests[i].alg;
1216 1.112 alnsn const uint8_t *key = selftests[i].key;
1217 1.112 alnsn int keylen = selftests[i].keylen;
1218 1.112 alnsn int txtlen = selftests[i].txtlen;
1219 1.112 alnsn
1220 1.112 alnsn printf("%s-%d ", alg, keylen);
1221 1.112 alnsn
1222 1.112 alnsn memset(&cs, 0, sizeof(cs));
1223 1.112 alnsn
1224 1.112 alnsn cs.sc_cfuncs = cryptfuncs_find(alg);
1225 1.112 alnsn if (cs.sc_cfuncs == NULL)
1226 1.112 alnsn panic("%s not implemented", alg);
1227 1.112 alnsn
1228 1.112 alnsn cs.sc_cdata.cf_blocksize = 8 * selftests[i].blocksize;
1229 1.112 alnsn cs.sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO1;
1230 1.112 alnsn cs.sc_cdata.cf_keylen = keylen;
1231 1.112 alnsn
1232 1.112 alnsn cs.sc_cdata.cf_priv = cs.sc_cfuncs->cf_init(keylen,
1233 1.112 alnsn key, &cs.sc_cdata.cf_blocksize);
1234 1.112 alnsn if (cs.sc_cdata.cf_priv == NULL)
1235 1.112 alnsn panic("cf_priv is NULL");
1236 1.112 alnsn if (cs.sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE)
1237 1.112 alnsn panic("bad block size %zu", cs.sc_cdata.cf_blocksize);
1238 1.112 alnsn
1239 1.112 alnsn cs.sc_cdata.cf_blocksize /= 8;
1240 1.112 alnsn
1241 1.112 alnsn buf = malloc(txtlen, M_DEVBUF, M_WAITOK);
1242 1.112 alnsn memcpy(buf, selftests[i].ptxt, txtlen);
1243 1.112 alnsn
1244 1.112 alnsn cgd_cipher(&cs, buf, buf, txtlen, selftests[i].blkno,
1245 1.112 alnsn selftests[i].secsize, CGD_CIPHER_ENCRYPT);
1246 1.112 alnsn if (memcmp(buf, selftests[i].ctxt, txtlen) != 0)
1247 1.112 alnsn panic("encryption is broken");
1248 1.112 alnsn
1249 1.112 alnsn cgd_cipher(&cs, buf, buf, txtlen, selftests[i].blkno,
1250 1.112 alnsn selftests[i].secsize, CGD_CIPHER_DECRYPT);
1251 1.112 alnsn if (memcmp(buf, selftests[i].ptxt, txtlen) != 0)
1252 1.112 alnsn panic("decryption is broken");
1253 1.112 alnsn
1254 1.112 alnsn free(buf, M_DEVBUF);
1255 1.112 alnsn cs.sc_cfuncs->cf_destroy(cs.sc_cdata.cf_priv);
1256 1.112 alnsn }
1257 1.112 alnsn
1258 1.112 alnsn printf("done\n");
1259 1.112 alnsn }
1260 1.112 alnsn
1261 1.113 kamil MODULE(MODULE_CLASS_DRIVER, cgd, "blowfish,des,dk_subr");
1262 1.74 jruoho
1263 1.58 haad #ifdef _MODULE
1264 1.66 dyoung CFDRIVER_DECL(cgd, DV_DISK, NULL);
1265 1.109 pgoyette
1266 1.109 pgoyette devmajor_t cgd_bmajor = -1, cgd_cmajor = -1;
1267 1.74 jruoho #endif
1268 1.58 haad
1269 1.58 haad static int
1270 1.58 haad cgd_modcmd(modcmd_t cmd, void *arg)
1271 1.58 haad {
1272 1.82 martin int error = 0;
1273 1.74 jruoho
1274 1.58 haad switch (cmd) {
1275 1.58 haad case MODULE_CMD_INIT:
1276 1.112 alnsn selftest();
1277 1.74 jruoho #ifdef _MODULE
1278 1.66 dyoung error = config_cfdriver_attach(&cgd_cd);
1279 1.66 dyoung if (error)
1280 1.66 dyoung break;
1281 1.66 dyoung
1282 1.66 dyoung error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
1283 1.66 dyoung if (error) {
1284 1.66 dyoung config_cfdriver_detach(&cgd_cd);
1285 1.114.4.1 pgoyette aprint_error("%s: unable to register cfattach for "
1286 1.109 pgoyette "%s, error %d\n", __func__, cgd_cd.cd_name, error);
1287 1.66 dyoung break;
1288 1.66 dyoung }
1289 1.109 pgoyette /*
1290 1.109 pgoyette * Attach the {b,c}devsw's
1291 1.109 pgoyette */
1292 1.109 pgoyette error = devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
1293 1.109 pgoyette &cgd_cdevsw, &cgd_cmajor);
1294 1.74 jruoho
1295 1.109 pgoyette /*
1296 1.109 pgoyette * If devsw_attach fails, remove from autoconf database
1297 1.109 pgoyette */
1298 1.66 dyoung if (error) {
1299 1.66 dyoung config_cfattach_detach(cgd_cd.cd_name, &cgd_ca);
1300 1.66 dyoung config_cfdriver_detach(&cgd_cd);
1301 1.109 pgoyette aprint_error("%s: unable to attach %s devsw, "
1302 1.109 pgoyette "error %d", __func__, cgd_cd.cd_name, error);
1303 1.66 dyoung break;
1304 1.66 dyoung }
1305 1.74 jruoho #endif
1306 1.58 haad break;
1307 1.58 haad
1308 1.58 haad case MODULE_CMD_FINI:
1309 1.74 jruoho #ifdef _MODULE
1310 1.109 pgoyette /*
1311 1.109 pgoyette * Remove {b,c}devsw's
1312 1.109 pgoyette */
1313 1.109 pgoyette devsw_detach(&cgd_bdevsw, &cgd_cdevsw);
1314 1.109 pgoyette
1315 1.109 pgoyette /*
1316 1.109 pgoyette * Now remove device from autoconf database
1317 1.109 pgoyette */
1318 1.66 dyoung error = config_cfattach_detach(cgd_cd.cd_name, &cgd_ca);
1319 1.109 pgoyette if (error) {
1320 1.110 pgoyette (void)devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
1321 1.109 pgoyette &cgd_cdevsw, &cgd_cmajor);
1322 1.109 pgoyette aprint_error("%s: failed to detach %s cfattach, "
1323 1.109 pgoyette "error %d\n", __func__, cgd_cd.cd_name, error);
1324 1.114.4.1 pgoyette break;
1325 1.109 pgoyette }
1326 1.109 pgoyette error = config_cfdriver_detach(&cgd_cd);
1327 1.109 pgoyette if (error) {
1328 1.110 pgoyette (void)config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
1329 1.110 pgoyette (void)devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
1330 1.109 pgoyette &cgd_cdevsw, &cgd_cmajor);
1331 1.109 pgoyette aprint_error("%s: failed to detach %s cfdriver, "
1332 1.109 pgoyette "error %d\n", __func__, cgd_cd.cd_name, error);
1333 1.66 dyoung break;
1334 1.109 pgoyette }
1335 1.74 jruoho #endif
1336 1.58 haad break;
1337 1.58 haad
1338 1.58 haad case MODULE_CMD_STAT:
1339 1.109 pgoyette error = ENOTTY;
1340 1.109 pgoyette break;
1341 1.58 haad default:
1342 1.109 pgoyette error = ENOTTY;
1343 1.109 pgoyette break;
1344 1.58 haad }
1345 1.58 haad
1346 1.58 haad return error;
1347 1.58 haad }
1348