xref: /netbsd/sys/dev/bio.c (revision f6c0f634)
1 /*	$NetBSD: bio.c,v 1.17 2020/12/19 01:12:21 thorpej 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.17 2020/12/19 01:12:21 thorpej 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/kmem.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 #include <sys/compat_stub.h>
47 
48 #include <dev/biovar.h>
49 #include <dev/sysmon/sysmonvar.h>
50 
51 #include "ioconf.h"
52 
53 struct bio_mapping {
54 	LIST_ENTRY(bio_mapping) bm_link;
55 	device_t bm_dev;
56 	int (*bm_ioctl)(device_t, u_long, void *);
57 };
58 
59 static LIST_HEAD(, bio_mapping) bios = LIST_HEAD_INITIALIZER(bios);
60 static kmutex_t bio_lock;
61 static bool bio_lock_initialized = false;
62 
63 static void	bio_initialize(void);
64 static int	bioclose(dev_t, int, int, struct lwp *);
65 static int	bioioctl(dev_t, u_long, void *, int, struct lwp *);
66 static int	bioopen(dev_t, int, int, struct lwp *);
67 
68 static int	bio_delegate_ioctl(void *, u_long, void *);
69 static struct	bio_mapping *bio_lookup(char *);
70 static int	bio_validate(void *);
71 
72 const struct cdevsw bio_cdevsw = {
73         .d_open = bioopen,
74 	.d_close = bioclose,
75 	.d_read = noread,
76 	.d_write = nowrite,
77 	.d_ioctl = bioioctl,
78         .d_stop = nostop,
79 	.d_tty = notty,
80 	.d_poll = nopoll,
81 	.d_mmap = nommap,
82 	.d_kqfilter = nokqfilter,
83 	.d_discard = nodiscard,
84 	.d_flag = D_OTHER | D_MPSAFE
85 };
86 
87 
88 static void
bio_initialize(void)89 bio_initialize(void)
90 {
91 	if (bio_lock_initialized)
92 		return;
93 
94 	mutex_init(&bio_lock, MUTEX_DEFAULT, IPL_VM);
95 	bio_lock_initialized = true;
96 }
97 
98 void
bioattach(int nunits)99 bioattach(int nunits)
100 {
101 	if (!bio_lock_initialized)
102 		bio_initialize();
103 }
104 
105 static int
bioopen(dev_t dev,int flags,int mode,struct lwp * l)106 bioopen(dev_t dev, int flags, int mode, struct lwp *l)
107 {
108 	return 0;
109 }
110 
111 static int
bioclose(dev_t dev,int flags,int mode,struct lwp * l)112 bioclose(dev_t dev, int flags, int mode, struct lwp *l)
113 {
114 	return 0;
115 }
116 
117 static int
bioioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)118 bioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct  lwp *l)
119 {
120 	struct bio_locate *locate;
121 	struct bio_common *common;
122 	char name[16];
123 	int error;
124 
125 	switch(cmd) {
126 	case BIOCLOCATE:
127 	case BIOCINQ:
128 	case BIOCDISK:
129 	case BIOCDISK_NOVOL:
130 	case BIOCVOL:
131 	case OBIOCDISK:
132 	case OBIOCVOL:
133 		error = kauth_authorize_device_passthru(l->l_cred, dev,
134 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
135 		if (error)
136 			return error;
137 		break;
138 	case BIOCBLINK:
139 	case BIOCSETSTATE:
140 	case BIOCVOLOPS:
141 		error = kauth_authorize_device_passthru(l->l_cred, dev,
142 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
143 		if (error)
144 			return error;
145 		break;
146 	case BIOCALARM: {
147 		struct bioc_alarm *alarm = (struct bioc_alarm *)addr;
148 		switch (alarm->ba_opcode) {
149 		case BIOC_SADISABLE:
150 		case BIOC_SAENABLE:
151 		case BIOC_SASILENCE:
152 		case BIOC_SATEST:
153 			error = kauth_authorize_device_passthru(l->l_cred, dev,
154 			    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
155 			if (error)
156 				return error;
157 			break;
158 		case BIOC_GASTATUS:
159 			error = kauth_authorize_device_passthru(l->l_cred, dev,
160 			    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
161 			if (error)
162 				return error;
163 			break;
164 		default:
165 			return EINVAL;
166 		}
167 		break;
168 	}
169 	default:
170 		return ENOTTY;
171 	}
172 
173 	switch (cmd) {
174 	case BIOCLOCATE:
175 		locate = addr;
176 		error = copyinstr(locate->bl_name, name, sizeof(name), NULL);
177 		if (error != 0)
178 			return error;
179 		locate->bl_cookie = bio_lookup(name);
180 		if (locate->bl_cookie == NULL)
181 			return ENOENT;
182 		break;
183 
184 	default:
185 		common = addr;
186 		mutex_enter(&bio_lock);
187 		if (!bio_validate(common->bc_cookie)) {
188 			mutex_exit(&bio_lock);
189 			return ENOENT;
190 		}
191 		mutex_exit(&bio_lock);
192 		MODULE_HOOK_CALL(compat_bio_30_hook,
193 		    (common->bc_cookie, cmd, addr, bio_delegate_ioctl),
194 		    enosys(), error);
195 		if (error == ENOSYS)
196 			error = bio_delegate_ioctl(common->bc_cookie, cmd,
197 			    addr);
198 		return error;
199 	}
200 	return 0;
201 }
202 
203 int
bio_register(device_t dev,int (* ioctl)(device_t,u_long,void *))204 bio_register(device_t dev, int (*ioctl)(device_t, u_long, void *))
205 {
206 	struct bio_mapping *bm;
207 
208 	if (!bio_lock_initialized)
209 		bio_initialize();
210 
211 	bm = kmem_zalloc(sizeof(*bm), KM_SLEEP);
212 	bm->bm_dev = dev;
213 	bm->bm_ioctl = ioctl;
214 	mutex_enter(&bio_lock);
215 	LIST_INSERT_HEAD(&bios, bm, bm_link);
216 	mutex_exit(&bio_lock);
217 	return 0;
218 }
219 
220 void
bio_unregister(device_t dev)221 bio_unregister(device_t dev)
222 {
223 	struct bio_mapping *bm, *next;
224 
225 	mutex_enter(&bio_lock);
226 	for (bm = LIST_FIRST(&bios); bm != NULL; bm = next) {
227 		next = LIST_NEXT(bm, bm_link);
228 
229 		if (dev == bm->bm_dev) {
230 			LIST_REMOVE(bm, bm_link);
231 			kmem_free(bm, sizeof(*bm));
232 		}
233 	}
234 	mutex_exit(&bio_lock);
235 }
236 
237 static struct bio_mapping *
bio_lookup(char * name)238 bio_lookup(char *name)
239 {
240 	struct bio_mapping *bm;
241 
242 	mutex_enter(&bio_lock);
243 	LIST_FOREACH(bm, &bios, bm_link) {
244 		if (strcmp(name, device_xname(bm->bm_dev)) == 0) {
245 			mutex_exit(&bio_lock);
246 			return bm;
247 		}
248 	}
249 	mutex_exit(&bio_lock);
250 	return NULL;
251 }
252 
253 static int
bio_validate(void * cookie)254 bio_validate(void *cookie)
255 {
256 	struct bio_mapping *bm;
257 
258 	LIST_FOREACH(bm, &bios, bm_link)
259 		if (bm == cookie)
260 			return 1;
261 
262 	return 0;
263 }
264 
265 static int
bio_delegate_ioctl(void * cookie,u_long cmd,void * addr)266 bio_delegate_ioctl(void *cookie, u_long cmd, void *addr)
267 {
268 	struct bio_mapping *bm = cookie;
269 
270 	return bm->bm_ioctl(bm->bm_dev, cmd, addr);
271 }
272 
273 void
bio_disk_to_envsys(envsys_data_t * edata,const struct bioc_disk * bd)274 bio_disk_to_envsys(envsys_data_t *edata, const struct bioc_disk *bd)
275 {
276 	switch (bd->bd_status) {
277 	case BIOC_SDONLINE:
278 		edata->value_cur = ENVSYS_DRIVE_ONLINE;
279 		edata->state = ENVSYS_SVALID;
280 		break;
281 	case BIOC_SDOFFLINE:
282 		edata->value_cur = ENVSYS_DRIVE_OFFLINE;
283 		edata->state = ENVSYS_SCRITICAL;
284 		break;
285 	default:
286 		edata->value_cur = ENVSYS_DRIVE_FAIL;
287 		edata->state = ENVSYS_SCRITICAL;
288 		break;
289 	}
290 }
291 
292 void
bio_vol_to_envsys(envsys_data_t * edata,const struct bioc_vol * bv)293 bio_vol_to_envsys(envsys_data_t *edata, const struct bioc_vol *bv)
294 {
295 	switch (bv->bv_status) {
296 	case BIOC_SVOFFLINE:
297 		edata->value_cur = ENVSYS_DRIVE_OFFLINE;
298 		edata->state = ENVSYS_SCRITICAL;
299 		break;
300 	case BIOC_SVDEGRADED:
301 		edata->value_cur = ENVSYS_DRIVE_PFAIL;
302 		edata->state = ENVSYS_SCRITICAL;
303 		break;
304 	case BIOC_SVBUILDING:
305 		edata->value_cur = ENVSYS_DRIVE_BUILD;
306 		edata->state = ENVSYS_SVALID;
307 		break;
308 	case BIOC_SVMIGRATING:
309 		edata->value_cur = ENVSYS_DRIVE_MIGRATING;
310 		edata->state = ENVSYS_SVALID;
311 		break;
312 	case BIOC_SVCHECKING:
313 		edata->value_cur = ENVSYS_DRIVE_CHECK;
314 		edata->state = ENVSYS_SVALID;
315 		break;
316 	case BIOC_SVREBUILD:
317 		edata->value_cur = ENVSYS_DRIVE_REBUILD;
318 		edata->state = ENVSYS_SCRITICAL;
319 		break;
320 	case BIOC_SVSCRUB:
321 	case BIOC_SVONLINE:
322 		edata->value_cur = ENVSYS_DRIVE_ONLINE;
323 		edata->state = ENVSYS_SVALID;
324 		break;
325 	case BIOC_SVINVALID:
326 		/* FALLTHROUGH */
327 	default:
328 		edata->value_cur = ENVSYS_DRIVE_EMPTY; /* unknown state */
329 		edata->state = ENVSYS_SINVALID;
330 		break;
331 	}
332 }
333