jcs's openbsd hax
openbsd
at jcs 239 lines 5.7 kB view raw
1/* $OpenBSD: bio.c,v 1.19 2023/11/15 23:57:45 dlg Exp $ */ 2 3/* 4 * Copyright (c) 2002 Niklas Hallqvist. All rights reserved. 5 * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>. 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/param.h> 31#include <sys/device.h> 32#include <sys/ioctl.h> 33#include <sys/malloc.h> 34#include <sys/tree.h> 35#include <sys/systm.h> 36 37#include <dev/biovar.h> 38 39struct bio_mapping { 40 RBT_ENTRY(bio_mapping) bm_link; 41 uintptr_t bm_cookie; 42 struct device *bm_dev; 43 int (*bm_ioctl)(struct device *, u_long, caddr_t); 44}; 45 46RBT_HEAD(bio_mappings, bio_mapping); 47 48static inline int 49bio_cookie_cmp(const struct bio_mapping *a, const struct bio_mapping *b) 50{ 51 if (a->bm_cookie < b->bm_cookie) 52 return (1); 53 if (a->bm_cookie > b->bm_cookie) 54 return (-1); 55 return (0); 56} 57 58RBT_PROTOTYPE(bio_mappings, bio_mapping, bm_link, bio_cookie_cmp); 59 60struct bio_mappings bios = RBT_INITIALIZER(); 61 62void bioattach(int); 63int bioclose(dev_t, int, int, struct proc *); 64int bioioctl(dev_t, u_long, caddr_t, int, struct proc *); 65int bioopen(dev_t, int, int, struct proc *); 66 67int bio_delegate_ioctl(struct bio_mapping *, u_long, caddr_t); 68struct bio_mapping *bio_lookup(char *); 69struct bio_mapping *bio_validate(void *); 70 71void 72bioattach(int nunits) 73{ 74} 75 76int 77bioopen(dev_t dev, int flags, int mode, struct proc *p) 78{ 79 return (0); 80} 81 82int 83bioclose(dev_t dev, int flags, int mode, struct proc *p) 84{ 85 return (0); 86} 87 88int 89bioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 90{ 91 struct bio_mapping *bm; 92 struct bio_locate *locate; 93 struct bio *bio; 94 char name[16]; 95 int error; 96 97 switch (cmd) { 98 case BIOCLOCATE: 99 locate = (struct bio_locate *)addr; 100 error = copyinstr(locate->bl_name, name, sizeof name, NULL); 101 if (error != 0) 102 return (error); 103 bm = bio_lookup(name); 104 if (bm == NULL) 105 return (ENOENT); 106 locate->bl_bio.bio_cookie = (void *)bm->bm_cookie; 107 break; 108 109 default: 110 bio = (struct bio *)addr; 111 bm = bio_validate(bio->bio_cookie); 112 if (bm == NULL) 113 return (ENOENT); 114 115 error = bio_delegate_ioctl(bm, cmd, addr); 116 break; 117 } 118 119 return (0); 120} 121 122int 123bio_register(struct device *dev, int (*ioctl)(struct device *, u_long, caddr_t)) 124{ 125 struct bio_mapping *bm; 126 127 bm = malloc(sizeof *bm, M_DEVBUF, M_NOWAIT); 128 if (bm == NULL) 129 return (ENOMEM); 130 bm->bm_dev = dev; 131 bm->bm_ioctl = ioctl; 132 do { 133 bm->bm_cookie = arc4random(); 134 /* lets hope we don't have 4 billion bio_registers */ 135 } while (RBT_INSERT(bio_mappings, &bios, bm) != NULL); 136 return (0); 137} 138 139void 140bio_unregister(struct device *dev) 141{ 142 struct bio_mapping *bm, *next; 143 144 RBT_FOREACH_SAFE(bm, bio_mappings, &bios, next) { 145 if (dev == bm->bm_dev) { 146 RBT_REMOVE(bio_mappings, &bios, bm); 147 free(bm, M_DEVBUF, sizeof(*bm)); 148 } 149 } 150} 151 152struct bio_mapping * 153bio_lookup(char *name) 154{ 155 struct bio_mapping *bm; 156 157 RBT_FOREACH(bm, bio_mappings, &bios) { 158 if (strcmp(name, bm->bm_dev->dv_xname) == 0) 159 return (bm); 160 } 161 162 return (NULL); 163} 164 165struct bio_mapping * 166bio_validate(void *cookie) 167{ 168 struct bio_mapping key = { .bm_cookie = (uintptr_t)cookie }; 169 170 return (RBT_FIND(bio_mappings, &bios, &key)); 171} 172 173int 174bio_delegate_ioctl(struct bio_mapping *bm, u_long cmd, caddr_t addr) 175{ 176 return (bm->bm_ioctl(bm->bm_dev, cmd, addr)); 177} 178 179void 180bio_info(struct bio_status *bs, int print, const char *fmt, ...) 181{ 182 va_list ap; 183 184 va_start(ap, fmt); 185 bio_status(bs, print, BIO_MSG_INFO, fmt, &ap); 186 va_end(ap); 187} 188 189void 190bio_warn(struct bio_status *bs, int print, const char *fmt, ...) 191{ 192 va_list ap; 193 194 va_start(ap, fmt); 195 bio_status(bs, print, BIO_MSG_WARN, fmt, &ap); 196 va_end(ap); 197} 198 199void 200bio_error(struct bio_status *bs, int print, const char *fmt, ...) 201{ 202 va_list ap; 203 204 va_start(ap, fmt); 205 bio_status(bs, print, BIO_MSG_ERROR, fmt, &ap); 206 va_end(ap); 207} 208 209void 210bio_status_init(struct bio_status *bs, struct device *dv) 211{ 212 bzero(bs, sizeof(struct bio_status)); 213 214 bs->bs_status = BIO_STATUS_UNKNOWN; 215 216 strlcpy(bs->bs_controller, dv->dv_xname, sizeof(bs->bs_controller)); 217} 218 219void 220bio_status(struct bio_status *bs, int print, int msg_type, const char *fmt, 221 va_list *ap) 222{ 223 int idx; 224 225 if (bs->bs_msg_count >= BIO_MSG_COUNT) { 226 printf("%s: insufficient message buffers\n", bs->bs_controller); 227 return; 228 } 229 230 idx = bs->bs_msg_count++; 231 232 bs->bs_msgs[idx].bm_type = msg_type; 233 vsnprintf(bs->bs_msgs[idx].bm_msg, BIO_MSG_LEN, fmt, *ap); 234 235 if (print) 236 printf("%s: %s\n", bs->bs_controller, bs->bs_msgs[idx].bm_msg); 237} 238 239RBT_GENERATE(bio_mappings, bio_mapping, bm_link, bio_cookie_cmp);