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 39 struct 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 46 RBT_HEAD(bio_mappings, bio_mapping); 47 48 static inline int 49 bio_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 58 RBT_PROTOTYPE(bio_mappings, bio_mapping, bm_link, bio_cookie_cmp); 59 60 struct bio_mappings bios = RBT_INITIALIZER(); 61 62 void bioattach(int); 63 int bioclose(dev_t, int, int, struct proc *); 64 int bioioctl(dev_t, u_long, caddr_t, int, struct proc *); 65 int bioopen(dev_t, int, int, struct proc *); 66 67 int bio_delegate_ioctl(struct bio_mapping *, u_long, caddr_t); 68 struct bio_mapping *bio_lookup(char *); 69 struct bio_mapping *bio_validate(void *); 70 71 void 72 bioattach(int nunits) 73 { 74 } 75 76 int 77 bioopen(dev_t dev, int flags, int mode, struct proc *p) 78 { 79 return (0); 80 } 81 82 int 83 bioclose(dev_t dev, int flags, int mode, struct proc *p) 84 { 85 return (0); 86 } 87 88 int 89 bioioctl(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 122 int 123 bio_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 139 void 140 bio_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 152 struct bio_mapping * 153 bio_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 165 struct bio_mapping * 166 bio_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 173 int 174 bio_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 179 void 180 bio_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 189 void 190 bio_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 199 void 200 bio_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 209 void 210 bio_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 219 void 220 bio_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 239 RBT_GENERATE(bio_mappings, bio_mapping, bm_link, bio_cookie_cmp); 240