bio.c revision 1.11.4.1 1 1.11.4.1 skrll /* $NetBSD: bio.c,v 1.11.4.1 2015/04/06 15:18:08 skrll Exp $ */
2 1.1 bouyer /* $OpenBSD: bio.c,v 1.9 2007/03/20 02:35:55 marco Exp $ */
3 1.1 bouyer
4 1.1 bouyer /*
5 1.1 bouyer * Copyright (c) 2002 Niklas Hallqvist. All rights reserved.
6 1.1 bouyer *
7 1.1 bouyer * Redistribution and use in source and binary forms, with or without
8 1.1 bouyer * modification, are permitted provided that the following conditions
9 1.1 bouyer * are met:
10 1.1 bouyer * 1. Redistributions of source code must retain the above copyright
11 1.1 bouyer * notice, this list of conditions and the following disclaimer.
12 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 bouyer * notice, this list of conditions and the following disclaimer in the
14 1.1 bouyer * documentation and/or other materials provided with the distribution.
15 1.1 bouyer *
16 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 1.1 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 1.1 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 1.1 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 1.1 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 1.1 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 1.1 bouyer */
27 1.1 bouyer
28 1.1 bouyer /* A device controller ioctl tunnelling device. */
29 1.1 bouyer
30 1.1 bouyer #include <sys/cdefs.h>
31 1.11.4.1 skrll __KERNEL_RCSID(0, "$NetBSD: bio.c,v 1.11.4.1 2015/04/06 15:18:08 skrll Exp $");
32 1.5 xtraeme
33 1.5 xtraeme #include "opt_compat_netbsd.h"
34 1.1 bouyer
35 1.1 bouyer #include <sys/param.h>
36 1.1 bouyer #include <sys/conf.h>
37 1.1 bouyer #include <sys/device.h>
38 1.1 bouyer #include <sys/event.h>
39 1.1 bouyer #include <sys/ioctl.h>
40 1.1 bouyer #include <sys/malloc.h>
41 1.1 bouyer #include <sys/queue.h>
42 1.1 bouyer #include <sys/systm.h>
43 1.1 bouyer #include <sys/mutex.h>
44 1.1 bouyer #include <sys/proc.h>
45 1.1 bouyer #include <sys/kauth.h>
46 1.1 bouyer
47 1.1 bouyer #include <dev/biovar.h>
48 1.11.4.1 skrll #include <dev/sysmon/sysmonvar.h>
49 1.1 bouyer
50 1.1 bouyer struct bio_mapping {
51 1.1 bouyer LIST_ENTRY(bio_mapping) bm_link;
52 1.9 cegger device_t bm_dev;
53 1.9 cegger int (*bm_ioctl)(device_t, u_long, void *);
54 1.1 bouyer };
55 1.1 bouyer
56 1.6 christos static LIST_HEAD(, bio_mapping) bios = LIST_HEAD_INITIALIZER(bios);
57 1.1 bouyer static kmutex_t bio_lock;
58 1.3 xtraeme static bool bio_lock_initialized = false;
59 1.1 bouyer
60 1.6 christos static void bio_initialize(void);
61 1.6 christos static int bioclose(dev_t, int, int, struct lwp *);
62 1.6 christos static int bioioctl(dev_t, u_long, void *, int, struct lwp *);
63 1.6 christos static int bioopen(dev_t, int, int, struct lwp *);
64 1.6 christos
65 1.6 christos static int bio_delegate_ioctl(void *, u_long, void *);
66 1.6 christos static struct bio_mapping *bio_lookup(char *);
67 1.6 christos static int bio_validate(void *);
68 1.6 christos
69 1.1 bouyer void bioattach(int);
70 1.1 bouyer
71 1.1 bouyer const struct cdevsw bio_cdevsw = {
72 1.10 dholland .d_open = bioopen,
73 1.10 dholland .d_close = bioclose,
74 1.10 dholland .d_read = noread,
75 1.10 dholland .d_write = nowrite,
76 1.10 dholland .d_ioctl = bioioctl,
77 1.10 dholland .d_stop = nostop,
78 1.10 dholland .d_tty = notty,
79 1.10 dholland .d_poll = nopoll,
80 1.10 dholland .d_mmap = nommap,
81 1.10 dholland .d_kqfilter = nokqfilter,
82 1.11 dholland .d_discard = nodiscard,
83 1.10 dholland .d_flag = D_OTHER | D_MPSAFE
84 1.1 bouyer };
85 1.1 bouyer
86 1.1 bouyer
87 1.6 christos static void
88 1.3 xtraeme bio_initialize(void)
89 1.3 xtraeme {
90 1.3 xtraeme if (bio_lock_initialized)
91 1.3 xtraeme return;
92 1.3 xtraeme
93 1.4 ad mutex_init(&bio_lock, MUTEX_DEFAULT, IPL_VM);
94 1.3 xtraeme bio_lock_initialized = true;
95 1.3 xtraeme }
96 1.3 xtraeme
97 1.3 xtraeme void
98 1.1 bouyer bioattach(int nunits)
99 1.1 bouyer {
100 1.3 xtraeme if (!bio_lock_initialized)
101 1.3 xtraeme bio_initialize();
102 1.1 bouyer }
103 1.1 bouyer
104 1.6 christos static int
105 1.1 bouyer bioopen(dev_t dev, int flags, int mode, struct lwp *l)
106 1.1 bouyer {
107 1.2 xtraeme return 0;
108 1.1 bouyer }
109 1.1 bouyer
110 1.6 christos static int
111 1.1 bouyer bioclose(dev_t dev, int flags, int mode, struct lwp *l)
112 1.1 bouyer {
113 1.2 xtraeme return 0;
114 1.1 bouyer }
115 1.1 bouyer
116 1.6 christos static int
117 1.1 bouyer bioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
118 1.1 bouyer {
119 1.1 bouyer struct bio_locate *locate;
120 1.1 bouyer struct bio_common *common;
121 1.1 bouyer char name[16];
122 1.1 bouyer int error;
123 1.1 bouyer
124 1.1 bouyer switch(cmd) {
125 1.1 bouyer case BIOCLOCATE:
126 1.1 bouyer case BIOCINQ:
127 1.1 bouyer case BIOCDISK:
128 1.5 xtraeme case BIOCDISK_NOVOL:
129 1.1 bouyer case BIOCVOL:
130 1.5 xtraeme #ifdef COMPAT_30
131 1.5 xtraeme case OBIOCDISK:
132 1.5 xtraeme case OBIOCVOL:
133 1.5 xtraeme #endif
134 1.1 bouyer error = kauth_authorize_device_passthru(l->l_cred, dev,
135 1.1 bouyer KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
136 1.1 bouyer if (error)
137 1.2 xtraeme return error;
138 1.1 bouyer break;
139 1.1 bouyer case BIOCBLINK:
140 1.1 bouyer case BIOCSETSTATE:
141 1.5 xtraeme case BIOCVOLOPS:
142 1.1 bouyer error = kauth_authorize_device_passthru(l->l_cred, dev,
143 1.1 bouyer KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
144 1.1 bouyer if (error)
145 1.2 xtraeme return error;
146 1.1 bouyer break;
147 1.1 bouyer case BIOCALARM: {
148 1.1 bouyer struct bioc_alarm *alarm = (struct bioc_alarm *)addr;
149 1.1 bouyer switch (alarm->ba_opcode) {
150 1.1 bouyer case BIOC_SADISABLE:
151 1.1 bouyer case BIOC_SAENABLE:
152 1.1 bouyer case BIOC_SASILENCE:
153 1.1 bouyer case BIOC_SATEST:
154 1.1 bouyer error = kauth_authorize_device_passthru(l->l_cred, dev,
155 1.1 bouyer KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
156 1.1 bouyer if (error)
157 1.2 xtraeme return error;
158 1.1 bouyer break;
159 1.1 bouyer case BIOC_GASTATUS:
160 1.1 bouyer error = kauth_authorize_device_passthru(l->l_cred, dev,
161 1.1 bouyer KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
162 1.1 bouyer if (error)
163 1.2 xtraeme return error;
164 1.1 bouyer break;
165 1.1 bouyer default:
166 1.1 bouyer return EINVAL;
167 1.1 bouyer }
168 1.1 bouyer break;
169 1.1 bouyer }
170 1.1 bouyer default:
171 1.1 bouyer return ENOTTY;
172 1.1 bouyer }
173 1.1 bouyer
174 1.1 bouyer switch (cmd) {
175 1.1 bouyer case BIOCLOCATE:
176 1.6 christos locate = addr;
177 1.5 xtraeme error = copyinstr(locate->bl_name, name, sizeof(name), NULL);
178 1.1 bouyer if (error != 0)
179 1.2 xtraeme return error;
180 1.1 bouyer locate->bl_cookie = bio_lookup(name);
181 1.1 bouyer if (locate->bl_cookie == NULL)
182 1.2 xtraeme return ENOENT;
183 1.1 bouyer break;
184 1.1 bouyer
185 1.1 bouyer default:
186 1.6 christos common = addr;
187 1.1 bouyer mutex_enter(&bio_lock);
188 1.1 bouyer if (!bio_validate(common->bc_cookie)) {
189 1.1 bouyer mutex_exit(&bio_lock);
190 1.2 xtraeme return ENOENT;
191 1.1 bouyer }
192 1.1 bouyer mutex_exit(&bio_lock);
193 1.5 xtraeme #ifdef COMPAT_30
194 1.5 xtraeme switch (cmd) {
195 1.6 christos case OBIOCDISK: {
196 1.6 christos struct bioc_disk *bd =
197 1.6 christos malloc(sizeof(*bd), M_DEVBUF, M_WAITOK|M_ZERO);
198 1.6 christos
199 1.6 christos (void)memcpy(bd, addr, sizeof(struct obioc_disk));
200 1.6 christos error = bio_delegate_ioctl(common->bc_cookie,
201 1.5 xtraeme BIOCDISK, bd);
202 1.5 xtraeme if (error) {
203 1.5 xtraeme free(bd, M_DEVBUF);
204 1.5 xtraeme return error;
205 1.5 xtraeme }
206 1.5 xtraeme
207 1.6 christos (void)memcpy(addr, bd, sizeof(struct obioc_disk));
208 1.5 xtraeme free(bd, M_DEVBUF);
209 1.5 xtraeme return 0;
210 1.6 christos }
211 1.6 christos case OBIOCVOL: {
212 1.6 christos struct bioc_vol *bv =
213 1.6 christos malloc(sizeof(*bv), M_DEVBUF, M_WAITOK|M_ZERO);
214 1.6 christos
215 1.6 christos (void)memcpy(bv, addr, sizeof(struct obioc_vol));
216 1.6 christos error = bio_delegate_ioctl(common->bc_cookie,
217 1.5 xtraeme BIOCVOL, bv);
218 1.5 xtraeme if (error) {
219 1.5 xtraeme free(bv, M_DEVBUF);
220 1.5 xtraeme return error;
221 1.5 xtraeme }
222 1.5 xtraeme
223 1.6 christos (void)memcpy(addr, bv, sizeof(struct obioc_vol));
224 1.5 xtraeme free(bv, M_DEVBUF);
225 1.5 xtraeme return 0;
226 1.6 christos }
227 1.5 xtraeme }
228 1.5 xtraeme #endif
229 1.6 christos error = bio_delegate_ioctl(common->bc_cookie, cmd, addr);
230 1.2 xtraeme return error;
231 1.1 bouyer }
232 1.2 xtraeme return 0;
233 1.1 bouyer }
234 1.1 bouyer
235 1.1 bouyer int
236 1.9 cegger bio_register(device_t dev, int (*ioctl)(device_t, u_long, void *))
237 1.1 bouyer {
238 1.1 bouyer struct bio_mapping *bm;
239 1.1 bouyer
240 1.3 xtraeme if (!bio_lock_initialized)
241 1.3 xtraeme bio_initialize();
242 1.3 xtraeme
243 1.5 xtraeme bm = malloc(sizeof(*bm), M_DEVBUF, M_NOWAIT|M_ZERO);
244 1.1 bouyer if (bm == NULL)
245 1.2 xtraeme return ENOMEM;
246 1.1 bouyer bm->bm_dev = dev;
247 1.1 bouyer bm->bm_ioctl = ioctl;
248 1.1 bouyer mutex_enter(&bio_lock);
249 1.1 bouyer LIST_INSERT_HEAD(&bios, bm, bm_link);
250 1.1 bouyer mutex_exit(&bio_lock);
251 1.2 xtraeme return 0;
252 1.1 bouyer }
253 1.1 bouyer
254 1.1 bouyer void
255 1.9 cegger bio_unregister(device_t dev)
256 1.1 bouyer {
257 1.1 bouyer struct bio_mapping *bm, *next;
258 1.1 bouyer
259 1.1 bouyer mutex_enter(&bio_lock);
260 1.1 bouyer for (bm = LIST_FIRST(&bios); bm != NULL; bm = next) {
261 1.1 bouyer next = LIST_NEXT(bm, bm_link);
262 1.1 bouyer
263 1.1 bouyer if (dev == bm->bm_dev) {
264 1.1 bouyer LIST_REMOVE(bm, bm_link);
265 1.1 bouyer free(bm, M_DEVBUF);
266 1.1 bouyer }
267 1.1 bouyer }
268 1.1 bouyer mutex_exit(&bio_lock);
269 1.1 bouyer }
270 1.1 bouyer
271 1.6 christos static struct bio_mapping *
272 1.1 bouyer bio_lookup(char *name)
273 1.1 bouyer {
274 1.1 bouyer struct bio_mapping *bm;
275 1.1 bouyer
276 1.1 bouyer mutex_enter(&bio_lock);
277 1.1 bouyer LIST_FOREACH(bm, &bios, bm_link) {
278 1.8 cegger if (strcmp(name, device_xname(bm->bm_dev)) == 0) {
279 1.1 bouyer mutex_exit(&bio_lock);
280 1.2 xtraeme return bm;
281 1.1 bouyer }
282 1.1 bouyer }
283 1.1 bouyer mutex_exit(&bio_lock);
284 1.2 xtraeme return NULL;
285 1.1 bouyer }
286 1.1 bouyer
287 1.6 christos static int
288 1.1 bouyer bio_validate(void *cookie)
289 1.1 bouyer {
290 1.1 bouyer struct bio_mapping *bm;
291 1.1 bouyer
292 1.2 xtraeme LIST_FOREACH(bm, &bios, bm_link)
293 1.2 xtraeme if (bm == cookie)
294 1.2 xtraeme return 1;
295 1.2 xtraeme
296 1.2 xtraeme return 0;
297 1.1 bouyer }
298 1.1 bouyer
299 1.6 christos static int
300 1.6 christos bio_delegate_ioctl(void *cookie, u_long cmd, void *addr)
301 1.1 bouyer {
302 1.6 christos struct bio_mapping *bm = cookie;
303 1.1 bouyer
304 1.2 xtraeme return bm->bm_ioctl(bm->bm_dev, cmd, addr);
305 1.1 bouyer }
306 1.11.4.1 skrll
307 1.11.4.1 skrll void
308 1.11.4.1 skrll bio_disk_to_envsys(envsys_data_t *edata, const struct bioc_disk *bd)
309 1.11.4.1 skrll {
310 1.11.4.1 skrll switch (bd->bd_status) {
311 1.11.4.1 skrll case BIOC_SDONLINE:
312 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_ONLINE;
313 1.11.4.1 skrll edata->state = ENVSYS_SVALID;
314 1.11.4.1 skrll break;
315 1.11.4.1 skrll case BIOC_SDOFFLINE:
316 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_OFFLINE;
317 1.11.4.1 skrll edata->state = ENVSYS_SCRITICAL;
318 1.11.4.1 skrll break;
319 1.11.4.1 skrll default:
320 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_FAIL;
321 1.11.4.1 skrll edata->state = ENVSYS_SCRITICAL;
322 1.11.4.1 skrll break;
323 1.11.4.1 skrll }
324 1.11.4.1 skrll }
325 1.11.4.1 skrll
326 1.11.4.1 skrll void
327 1.11.4.1 skrll bio_vol_to_envsys(envsys_data_t *edata, const struct bioc_vol *bv)
328 1.11.4.1 skrll {
329 1.11.4.1 skrll switch (bv->bv_status) {
330 1.11.4.1 skrll case BIOC_SVOFFLINE:
331 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_OFFLINE;
332 1.11.4.1 skrll edata->state = ENVSYS_SCRITICAL;
333 1.11.4.1 skrll break;
334 1.11.4.1 skrll case BIOC_SVDEGRADED:
335 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_PFAIL;
336 1.11.4.1 skrll edata->state = ENVSYS_SCRITICAL;
337 1.11.4.1 skrll break;
338 1.11.4.1 skrll case BIOC_SVBUILDING:
339 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_BUILD;
340 1.11.4.1 skrll edata->state = ENVSYS_SVALID;
341 1.11.4.1 skrll break;
342 1.11.4.1 skrll case BIOC_SVMIGRATING:
343 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_MIGRATING;
344 1.11.4.1 skrll edata->state = ENVSYS_SVALID;
345 1.11.4.1 skrll break;
346 1.11.4.1 skrll case BIOC_SVCHECKING:
347 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_CHECK;
348 1.11.4.1 skrll edata->state = ENVSYS_SVALID;
349 1.11.4.1 skrll break;
350 1.11.4.1 skrll case BIOC_SVREBUILD:
351 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_REBUILD;
352 1.11.4.1 skrll edata->state = ENVSYS_SCRITICAL;
353 1.11.4.1 skrll break;
354 1.11.4.1 skrll case BIOC_SVSCRUB:
355 1.11.4.1 skrll case BIOC_SVONLINE:
356 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_ONLINE;
357 1.11.4.1 skrll edata->state = ENVSYS_SVALID;
358 1.11.4.1 skrll break;
359 1.11.4.1 skrll case BIOC_SVINVALID:
360 1.11.4.1 skrll /* FALLTHROUGH */
361 1.11.4.1 skrll default:
362 1.11.4.1 skrll edata->value_cur = ENVSYS_DRIVE_EMPTY; /* unknown state */
363 1.11.4.1 skrll edata->state = ENVSYS_SINVALID;
364 1.11.4.1 skrll break;
365 1.11.4.1 skrll }
366 1.11.4.1 skrll }
367