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