Home | History | Annotate | Line # | Download | only in dev
bio.c revision 1.13.16.3
      1  1.13.16.3  pgoyette /*	$NetBSD: bio.c,v 1.13.16.3 2018/09/18 01:15:57 pgoyette 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.16.3  pgoyette __KERNEL_RCSID(0, "$NetBSD: bio.c,v 1.13.16.3 2018/09/18 01:15:57 pgoyette 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.16.1  pgoyette #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.13.16.2  pgoyette /* Hook up the compat_bio_30 routine */
    118  1.13.16.3  pgoyette COMPAT_CALL_HOOK_DECL(compat_bio_30_hook, f,
    119  1.13.16.3  pgoyette     (void * cookie, u_long cmd, void *addr, int(*ff)(void *, u_long, void *)),
    120  1.13.16.3  pgoyette     (cookie, cmd, addr, ff), enosys());
    121  1.13.16.2  pgoyette COMPAT_CALL_HOOK(compat_bio_30_hook, f,
    122  1.13.16.2  pgoyette     (void * cookie, u_long cmd, void *addr, int(*ff)(void *, u_long, void *)),
    123  1.13.16.2  pgoyette     (cookie, cmd, addr, ff), enosys());
    124  1.13.16.2  pgoyette 
    125        1.6  christos static int
    126        1.1    bouyer bioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct  lwp *l)
    127        1.1    bouyer {
    128        1.1    bouyer 	struct bio_locate *locate;
    129        1.1    bouyer 	struct bio_common *common;
    130        1.1    bouyer 	char name[16];
    131        1.1    bouyer 	int error;
    132        1.1    bouyer 
    133        1.1    bouyer 	switch(cmd) {
    134        1.1    bouyer 	case BIOCLOCATE:
    135        1.1    bouyer 	case BIOCINQ:
    136        1.1    bouyer 	case BIOCDISK:
    137        1.5   xtraeme 	case BIOCDISK_NOVOL:
    138        1.1    bouyer 	case BIOCVOL:
    139        1.5   xtraeme 	case OBIOCDISK:
    140        1.5   xtraeme 	case OBIOCVOL:
    141        1.1    bouyer 		error = kauth_authorize_device_passthru(l->l_cred, dev,
    142        1.1    bouyer 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
    143        1.1    bouyer 		if (error)
    144        1.2   xtraeme 			return error;
    145        1.1    bouyer 		break;
    146        1.1    bouyer 	case BIOCBLINK:
    147        1.1    bouyer 	case BIOCSETSTATE:
    148        1.5   xtraeme 	case BIOCVOLOPS:
    149        1.1    bouyer 		error = kauth_authorize_device_passthru(l->l_cred, dev,
    150        1.1    bouyer 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
    151        1.1    bouyer 		if (error)
    152        1.2   xtraeme 			return error;
    153        1.1    bouyer 		break;
    154        1.1    bouyer 	case BIOCALARM: {
    155        1.1    bouyer 		struct bioc_alarm *alarm = (struct bioc_alarm *)addr;
    156        1.1    bouyer 		switch (alarm->ba_opcode) {
    157        1.1    bouyer 		case BIOC_SADISABLE:
    158        1.1    bouyer 		case BIOC_SAENABLE:
    159        1.1    bouyer 		case BIOC_SASILENCE:
    160        1.1    bouyer 		case BIOC_SATEST:
    161        1.1    bouyer 			error = kauth_authorize_device_passthru(l->l_cred, dev,
    162        1.1    bouyer 			    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
    163        1.1    bouyer 			if (error)
    164        1.2   xtraeme 				return error;
    165        1.1    bouyer 			break;
    166        1.1    bouyer 		case BIOC_GASTATUS:
    167        1.1    bouyer 			error = kauth_authorize_device_passthru(l->l_cred, dev,
    168        1.1    bouyer 			    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
    169        1.1    bouyer 			if (error)
    170        1.2   xtraeme 				return error;
    171        1.1    bouyer 			break;
    172        1.1    bouyer 		default:
    173        1.1    bouyer 			return EINVAL;
    174        1.1    bouyer 		}
    175        1.1    bouyer 		break;
    176        1.1    bouyer 	}
    177        1.1    bouyer 	default:
    178        1.1    bouyer 		return ENOTTY;
    179        1.1    bouyer 	}
    180        1.1    bouyer 
    181        1.1    bouyer 	switch (cmd) {
    182        1.1    bouyer 	case BIOCLOCATE:
    183        1.6  christos 		locate = addr;
    184        1.5   xtraeme 		error = copyinstr(locate->bl_name, name, sizeof(name), NULL);
    185        1.1    bouyer 		if (error != 0)
    186        1.2   xtraeme 			return error;
    187        1.1    bouyer 		locate->bl_cookie = bio_lookup(name);
    188        1.1    bouyer 		if (locate->bl_cookie == NULL)
    189        1.2   xtraeme 			return ENOENT;
    190        1.1    bouyer 		break;
    191        1.1    bouyer 
    192        1.1    bouyer 	default:
    193        1.6  christos 		common = addr;
    194        1.1    bouyer 		mutex_enter(&bio_lock);
    195        1.1    bouyer 		if (!bio_validate(common->bc_cookie)) {
    196        1.1    bouyer 			mutex_exit(&bio_lock);
    197        1.2   xtraeme 			return ENOENT;
    198        1.1    bouyer 		}
    199        1.1    bouyer 		mutex_exit(&bio_lock);
    200  1.13.16.2  pgoyette 		error = compat_bio_30_hook_f_call(common->bc_cookie, cmd, addr,
    201  1.13.16.1  pgoyette 		    bio_delegate_ioctl);
    202  1.13.16.1  pgoyette 		if (error == ENOSYS)
    203  1.13.16.1  pgoyette 			error = bio_delegate_ioctl(common->bc_cookie, cmd,
    204  1.13.16.1  pgoyette 			    addr);
    205        1.2   xtraeme 		return error;
    206        1.1    bouyer 	}
    207        1.2   xtraeme 	return 0;
    208        1.1    bouyer }
    209        1.1    bouyer 
    210        1.1    bouyer int
    211        1.9    cegger bio_register(device_t dev, int (*ioctl)(device_t, u_long, void *))
    212        1.1    bouyer {
    213        1.1    bouyer 	struct bio_mapping *bm;
    214        1.1    bouyer 
    215        1.3   xtraeme 	if (!bio_lock_initialized)
    216        1.3   xtraeme 		bio_initialize();
    217        1.3   xtraeme 
    218        1.5   xtraeme 	bm = malloc(sizeof(*bm), M_DEVBUF, M_NOWAIT|M_ZERO);
    219        1.1    bouyer 	if (bm == NULL)
    220        1.2   xtraeme 		return ENOMEM;
    221        1.1    bouyer 	bm->bm_dev = dev;
    222        1.1    bouyer 	bm->bm_ioctl = ioctl;
    223        1.1    bouyer 	mutex_enter(&bio_lock);
    224        1.1    bouyer 	LIST_INSERT_HEAD(&bios, bm, bm_link);
    225        1.1    bouyer 	mutex_exit(&bio_lock);
    226        1.2   xtraeme 	return 0;
    227        1.1    bouyer }
    228        1.1    bouyer 
    229        1.1    bouyer void
    230        1.9    cegger bio_unregister(device_t dev)
    231        1.1    bouyer {
    232        1.1    bouyer 	struct bio_mapping *bm, *next;
    233        1.1    bouyer 
    234        1.1    bouyer 	mutex_enter(&bio_lock);
    235        1.1    bouyer 	for (bm = LIST_FIRST(&bios); bm != NULL; bm = next) {
    236        1.1    bouyer 		next = LIST_NEXT(bm, bm_link);
    237        1.1    bouyer 
    238        1.1    bouyer 		if (dev == bm->bm_dev) {
    239        1.1    bouyer 			LIST_REMOVE(bm, bm_link);
    240        1.1    bouyer 			free(bm, M_DEVBUF);
    241        1.1    bouyer 		}
    242        1.1    bouyer 	}
    243        1.1    bouyer 	mutex_exit(&bio_lock);
    244        1.1    bouyer }
    245        1.1    bouyer 
    246        1.6  christos static struct bio_mapping *
    247        1.1    bouyer bio_lookup(char *name)
    248        1.1    bouyer {
    249        1.1    bouyer 	struct bio_mapping *bm;
    250        1.1    bouyer 
    251        1.1    bouyer 	mutex_enter(&bio_lock);
    252        1.1    bouyer 	LIST_FOREACH(bm, &bios, bm_link) {
    253        1.8    cegger 		if (strcmp(name, device_xname(bm->bm_dev)) == 0) {
    254        1.1    bouyer 			mutex_exit(&bio_lock);
    255        1.2   xtraeme 			return bm;
    256        1.1    bouyer 		}
    257        1.1    bouyer 	}
    258        1.1    bouyer 	mutex_exit(&bio_lock);
    259        1.2   xtraeme 	return NULL;
    260        1.1    bouyer }
    261        1.1    bouyer 
    262        1.6  christos static int
    263        1.1    bouyer bio_validate(void *cookie)
    264        1.1    bouyer {
    265        1.1    bouyer 	struct bio_mapping *bm;
    266        1.1    bouyer 
    267        1.2   xtraeme 	LIST_FOREACH(bm, &bios, bm_link)
    268        1.2   xtraeme 		if (bm == cookie)
    269        1.2   xtraeme 			return 1;
    270        1.2   xtraeme 
    271        1.2   xtraeme 	return 0;
    272        1.1    bouyer }
    273        1.1    bouyer 
    274        1.6  christos static int
    275        1.6  christos bio_delegate_ioctl(void *cookie, u_long cmd, void *addr)
    276        1.1    bouyer {
    277        1.6  christos 	struct bio_mapping *bm = cookie;
    278        1.1    bouyer 
    279        1.2   xtraeme 	return bm->bm_ioctl(bm->bm_dev, cmd, addr);
    280        1.1    bouyer }
    281       1.12  christos 
    282       1.12  christos void
    283       1.12  christos bio_disk_to_envsys(envsys_data_t *edata, const struct bioc_disk *bd)
    284       1.12  christos {
    285       1.12  christos 	switch (bd->bd_status) {
    286       1.12  christos 	case BIOC_SDONLINE:
    287       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_ONLINE;
    288       1.12  christos 		edata->state = ENVSYS_SVALID;
    289       1.12  christos 		break;
    290       1.12  christos 	case BIOC_SDOFFLINE:
    291       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_OFFLINE;
    292       1.12  christos 		edata->state = ENVSYS_SCRITICAL;
    293       1.12  christos 		break;
    294       1.12  christos 	default:
    295       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_FAIL;
    296       1.12  christos 		edata->state = ENVSYS_SCRITICAL;
    297       1.12  christos 		break;
    298       1.12  christos 	}
    299       1.12  christos }
    300       1.12  christos 
    301       1.12  christos void
    302       1.12  christos bio_vol_to_envsys(envsys_data_t *edata, const struct bioc_vol *bv)
    303       1.12  christos {
    304       1.12  christos 	switch (bv->bv_status) {
    305       1.12  christos 	case BIOC_SVOFFLINE:
    306       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_OFFLINE;
    307       1.12  christos 		edata->state = ENVSYS_SCRITICAL;
    308       1.12  christos 		break;
    309       1.12  christos 	case BIOC_SVDEGRADED:
    310       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_PFAIL;
    311       1.12  christos 		edata->state = ENVSYS_SCRITICAL;
    312       1.12  christos 		break;
    313       1.12  christos 	case BIOC_SVBUILDING:
    314       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_BUILD;
    315       1.12  christos 		edata->state = ENVSYS_SVALID;
    316       1.12  christos 		break;
    317       1.12  christos 	case BIOC_SVMIGRATING:
    318       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_MIGRATING;
    319       1.12  christos 		edata->state = ENVSYS_SVALID;
    320       1.12  christos 		break;
    321       1.12  christos 	case BIOC_SVCHECKING:
    322       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_CHECK;
    323       1.12  christos 		edata->state = ENVSYS_SVALID;
    324       1.12  christos 		break;
    325       1.12  christos 	case BIOC_SVREBUILD:
    326       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_REBUILD;
    327       1.12  christos 		edata->state = ENVSYS_SCRITICAL;
    328       1.12  christos 		break;
    329       1.12  christos 	case BIOC_SVSCRUB:
    330       1.12  christos 	case BIOC_SVONLINE:
    331       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_ONLINE;
    332       1.12  christos 		edata->state = ENVSYS_SVALID;
    333       1.12  christos 		break;
    334       1.12  christos 	case BIOC_SVINVALID:
    335       1.12  christos 		/* FALLTHROUGH */
    336       1.12  christos 	default:
    337       1.12  christos 		edata->value_cur = ENVSYS_DRIVE_EMPTY; /* unknown state */
    338       1.12  christos 		edata->state = ENVSYS_SINVALID;
    339       1.12  christos 		break;
    340       1.12  christos 	}
    341       1.12  christos }
    342