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