1 1.87 hannken /* $NetBSD: md.c,v 1.87 2023/01/13 15:46:40 hannken Exp $ */ 2 1.1 gwr 3 1.1 gwr /* 4 1.1 gwr * Copyright (c) 1995 Gordon W. Ross, Leo Weppelman. 5 1.1 gwr * All rights reserved. 6 1.1 gwr * 7 1.1 gwr * Redistribution and use in source and binary forms, with or without 8 1.1 gwr * modification, are permitted provided that the following conditions 9 1.1 gwr * are met: 10 1.1 gwr * 1. Redistributions of source code must retain the above copyright 11 1.1 gwr * notice, this list of conditions and the following disclaimer. 12 1.1 gwr * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 gwr * notice, this list of conditions and the following disclaimer in the 14 1.1 gwr * documentation and/or other materials provided with the distribution. 15 1.1 gwr * 16 1.1 gwr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 gwr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 gwr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 gwr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 gwr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 gwr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 gwr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 gwr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 gwr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 gwr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 gwr */ 27 1.1 gwr 28 1.1 gwr /* 29 1.11 pk * This implements a general-purpose memory-disk. 30 1.13 jeremy * See md.h for notes on the config types. 31 1.1 gwr * 32 1.1 gwr * Note that this driver provides the same functionality 33 1.1 gwr * as the MFS filesystem hack, but this is better because 34 1.1 gwr * you can use this for any filesystem type you'd like! 35 1.1 gwr * 36 1.1 gwr * Credit for most of the kmem ramdisk code goes to: 37 1.1 gwr * Leo Weppelman (atari) and Phil Nelson (pc532) 38 1.11 pk * Credit for the ideas behind the "user space memory" code goes 39 1.1 gwr * to the authors of the MFS implementation. 40 1.1 gwr */ 41 1.27 lukem 42 1.27 lukem #include <sys/cdefs.h> 43 1.87 hannken __KERNEL_RCSID(0, "$NetBSD: md.c,v 1.87 2023/01/13 15:46:40 hannken Exp $"); 44 1.16 mrg 45 1.64 pooka #ifdef _KERNEL_OPT 46 1.19 jonathan #include "opt_md.h" 47 1.64 pooka #else 48 1.64 pooka #define MEMORY_DISK_SERVER 1 49 1.64 pooka #endif 50 1.1 gwr 51 1.1 gwr #include <sys/param.h> 52 1.7 gwr #include <sys/kernel.h> 53 1.86 thorpej #include <sys/kmem.h> 54 1.1 gwr #include <sys/systm.h> 55 1.1 gwr #include <sys/buf.h> 56 1.39 yamt #include <sys/bufq.h> 57 1.1 gwr #include <sys/device.h> 58 1.4 thorpej #include <sys/disk.h> 59 1.60 dyoung #include <sys/stat.h> 60 1.8 leo #include <sys/proc.h> 61 1.8 leo #include <sys/conf.h> 62 1.14 leo #include <sys/disklabel.h> 63 1.23 mrg 64 1.23 mrg #include <uvm/uvm_extern.h> 65 1.1 gwr 66 1.11 pk #include <dev/md.h> 67 1.1 gwr 68 1.75 christos #include "ioconf.h" 69 1.1 gwr /* 70 1.49 dsl * The user-space functionality is included by default. 71 1.11 pk * Use `options MEMORY_DISK_SERVER=0' to turn it off. 72 1.1 gwr */ 73 1.11 pk #ifndef MEMORY_DISK_SERVER 74 1.49 dsl #error MEMORY_DISK_SERVER should be defined by opt_md.h 75 1.33 atatat #endif /* MEMORY_DISK_SERVER */ 76 1.1 gwr 77 1.1 gwr /* 78 1.21 tsutsui * We should use the raw partition for ioctl. 79 1.1 gwr */ 80 1.21 tsutsui #define MD_UNIT(unit) DISKUNIT(unit) 81 1.1 gwr 82 1.1 gwr /* autoconfig stuff... */ 83 1.1 gwr 84 1.11 pk struct md_softc { 85 1.63 hannken device_t sc_dev; /* Self. */ 86 1.4 thorpej struct disk sc_dkdev; /* hook for generic disk handling */ 87 1.11 pk struct md_conf sc_md; 88 1.65 hannken kmutex_t sc_lock; /* Protect self. */ 89 1.66 hannken kcondvar_t sc_cv; /* Wait here for work. */ 90 1.42 yamt struct bufq_state *sc_buflist; 91 1.1 gwr }; 92 1.11 pk /* shorthand for fields in sc_md: */ 93 1.11 pk #define sc_addr sc_md.md_addr 94 1.11 pk #define sc_size sc_md.md_size 95 1.11 pk #define sc_type sc_md.md_type 96 1.1 gwr 97 1.54 cegger static void md_attach(device_t, device_t, void *); 98 1.59 dyoung static int md_detach(device_t, int); 99 1.38 thorpej 100 1.38 thorpej static dev_type_open(mdopen); 101 1.38 thorpej static dev_type_close(mdclose); 102 1.38 thorpej static dev_type_read(mdread); 103 1.38 thorpej static dev_type_write(mdwrite); 104 1.38 thorpej static dev_type_ioctl(mdioctl); 105 1.38 thorpej static dev_type_strategy(mdstrategy); 106 1.38 thorpej static dev_type_size(mdsize); 107 1.31 gehenna 108 1.31 gehenna const struct bdevsw md_bdevsw = { 109 1.69 dholland .d_open = mdopen, 110 1.69 dholland .d_close = mdclose, 111 1.69 dholland .d_strategy = mdstrategy, 112 1.69 dholland .d_ioctl = mdioctl, 113 1.69 dholland .d_dump = nodump, 114 1.69 dholland .d_psize = mdsize, 115 1.70 dholland .d_discard = nodiscard, 116 1.69 dholland .d_flag = D_DISK | D_MPSAFE 117 1.31 gehenna }; 118 1.31 gehenna 119 1.31 gehenna const struct cdevsw md_cdevsw = { 120 1.69 dholland .d_open = mdopen, 121 1.69 dholland .d_close = mdclose, 122 1.69 dholland .d_read = mdread, 123 1.69 dholland .d_write = mdwrite, 124 1.69 dholland .d_ioctl = mdioctl, 125 1.69 dholland .d_stop = nostop, 126 1.69 dholland .d_tty = notty, 127 1.69 dholland .d_poll = nopoll, 128 1.69 dholland .d_mmap = nommap, 129 1.69 dholland .d_kqfilter = nokqfilter, 130 1.71 dholland .d_discard = nodiscard, 131 1.83 ad .d_flag = D_DISK | D_MPSAFE 132 1.31 gehenna }; 133 1.31 gehenna 134 1.84 maxv static const struct dkdriver mddkdriver = { 135 1.82 hannken .d_strategy = mdstrategy, 136 1.82 hannken .d_minphys = minphys 137 1.74 mlelstv }; 138 1.4 thorpej 139 1.59 dyoung CFATTACH_DECL3_NEW(md, sizeof(struct md_softc), 140 1.59 dyoung 0, md_attach, md_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); 141 1.4 thorpej 142 1.63 hannken static kmutex_t md_device_lock; /* Protect unit creation / deletion. */ 143 1.58 manu extern size_t md_root_size; 144 1.58 manu 145 1.63 hannken static void md_set_disklabel(struct md_softc *); 146 1.63 hannken 147 1.7 gwr /* 148 1.7 gwr * This is called if we are configured as a pseudo-device 149 1.7 gwr */ 150 1.7 gwr void 151 1.38 thorpej mdattach(int n) 152 1.1 gwr { 153 1.7 gwr 154 1.63 hannken mutex_init(&md_device_lock, MUTEX_DEFAULT, IPL_NONE); 155 1.63 hannken if (config_cfattach_attach(md_cd.cd_name, &md_ca)) { 156 1.63 hannken aprint_error("%s: cfattach_attach failed\n", md_cd.cd_name); 157 1.7 gwr return; 158 1.7 gwr } 159 1.1 gwr } 160 1.1 gwr 161 1.1 gwr static void 162 1.59 dyoung md_attach(device_t parent, device_t self, void *aux) 163 1.1 gwr { 164 1.54 cegger struct md_softc *sc = device_private(self); 165 1.1 gwr 166 1.63 hannken sc->sc_dev = self; 167 1.66 hannken sc->sc_type = MD_UNCONFIGURED; 168 1.65 hannken mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 169 1.65 hannken cv_init(&sc->sc_cv, "mdidle"); 170 1.42 yamt bufq_alloc(&sc->sc_buflist, "fcfs", 0); 171 1.22 thorpej 172 1.1 gwr /* XXX - Could accept aux info here to set the config. */ 173 1.11 pk #ifdef MEMORY_DISK_HOOKS 174 1.1 gwr /* 175 1.1 gwr * This external function might setup a pre-loaded disk. 176 1.11 pk * All it would need to do is setup the md_conf struct. 177 1.25 tsutsui * See sys/dev/md_root.c for an example. 178 1.1 gwr */ 179 1.54 cegger md_attach_hook(device_unit(self), &sc->sc_md); 180 1.1 gwr #endif 181 1.4 thorpej 182 1.4 thorpej /* 183 1.4 thorpej * Initialize and attach the disk structure. 184 1.4 thorpej */ 185 1.54 cegger disk_init(&sc->sc_dkdev, device_xname(self), &mddkdriver); 186 1.4 thorpej disk_attach(&sc->sc_dkdev); 187 1.55 cegger 188 1.63 hannken if (sc->sc_type != MD_UNCONFIGURED) 189 1.63 hannken md_set_disklabel(sc); 190 1.63 hannken 191 1.55 cegger if (!pmf_device_register(self, NULL, NULL)) 192 1.55 cegger aprint_error_dev(self, "couldn't establish power handler\n"); 193 1.1 gwr } 194 1.1 gwr 195 1.59 dyoung static int 196 1.59 dyoung md_detach(device_t self, int flags) 197 1.59 dyoung { 198 1.59 dyoung struct md_softc *sc = device_private(self); 199 1.59 dyoung int rc; 200 1.59 dyoung 201 1.59 dyoung rc = 0; 202 1.59 dyoung mutex_enter(&sc->sc_dkdev.dk_openlock); 203 1.66 hannken if (sc->sc_dkdev.dk_openmask == 0 && sc->sc_type == MD_UNCONFIGURED) 204 1.59 dyoung ; /* nothing to do */ 205 1.59 dyoung else if ((flags & DETACH_FORCE) == 0) 206 1.59 dyoung rc = EBUSY; 207 1.59 dyoung mutex_exit(&sc->sc_dkdev.dk_openlock); 208 1.59 dyoung 209 1.59 dyoung if (rc != 0) 210 1.59 dyoung return rc; 211 1.59 dyoung 212 1.59 dyoung pmf_device_deregister(self); 213 1.59 dyoung disk_detach(&sc->sc_dkdev); 214 1.59 dyoung disk_destroy(&sc->sc_dkdev); 215 1.59 dyoung bufq_free(sc->sc_buflist); 216 1.65 hannken mutex_destroy(&sc->sc_lock); 217 1.65 hannken cv_destroy(&sc->sc_cv); 218 1.59 dyoung return 0; 219 1.59 dyoung } 220 1.59 dyoung 221 1.1 gwr /* 222 1.1 gwr * operational routines: 223 1.1 gwr * open, close, read, write, strategy, 224 1.1 gwr * ioctl, dump, size 225 1.1 gwr */ 226 1.1 gwr 227 1.11 pk #if MEMORY_DISK_SERVER 228 1.38 thorpej static int md_server_loop(struct md_softc *sc); 229 1.38 thorpej static int md_ioctl_server(struct md_softc *sc, struct md_conf *umd, 230 1.43 christos struct lwp *l); 231 1.33 atatat #endif /* MEMORY_DISK_SERVER */ 232 1.38 thorpej static int md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd, 233 1.43 christos struct lwp *l); 234 1.1 gwr 235 1.38 thorpej static int 236 1.21 tsutsui mdsize(dev_t dev) 237 1.1 gwr { 238 1.11 pk struct md_softc *sc; 239 1.65 hannken int res; 240 1.1 gwr 241 1.54 cegger sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 242 1.1 gwr if (sc == NULL) 243 1.1 gwr return 0; 244 1.1 gwr 245 1.65 hannken mutex_enter(&sc->sc_lock); 246 1.11 pk if (sc->sc_type == MD_UNCONFIGURED) 247 1.65 hannken res = 0; 248 1.65 hannken else 249 1.65 hannken res = sc->sc_size >> DEV_BSHIFT; 250 1.65 hannken mutex_exit(&sc->sc_lock); 251 1.1 gwr 252 1.65 hannken return res; 253 1.1 gwr } 254 1.1 gwr 255 1.38 thorpej static int 256 1.47 christos mdopen(dev_t dev, int flag, int fmt, struct lwp *l) 257 1.1 gwr { 258 1.21 tsutsui int unit; 259 1.60 dyoung int part = DISKPART(dev); 260 1.60 dyoung int pmask = 1 << part; 261 1.63 hannken cfdata_t cf; 262 1.11 pk struct md_softc *sc; 263 1.60 dyoung struct disk *dk; 264 1.67 tsutsui #ifdef MEMORY_DISK_HOOKS 265 1.67 tsutsui bool configured; 266 1.67 tsutsui #endif 267 1.1 gwr 268 1.63 hannken mutex_enter(&md_device_lock); 269 1.21 tsutsui unit = MD_UNIT(dev); 270 1.53 drochner sc = device_lookup_private(&md_cd, unit); 271 1.63 hannken if (sc == NULL) { 272 1.63 hannken if (part != RAW_PART) { 273 1.63 hannken mutex_exit(&md_device_lock); 274 1.63 hannken return ENXIO; 275 1.63 hannken } 276 1.86 thorpej cf = kmem_zalloc(sizeof(*cf), KM_SLEEP); 277 1.63 hannken cf->cf_name = md_cd.cd_name; 278 1.63 hannken cf->cf_atname = md_cd.cd_name; 279 1.63 hannken cf->cf_unit = unit; 280 1.63 hannken cf->cf_fstate = FSTATE_STAR; 281 1.63 hannken sc = device_private(config_attach_pseudo(cf)); 282 1.63 hannken if (sc == NULL) { 283 1.63 hannken mutex_exit(&md_device_lock); 284 1.63 hannken return ENOMEM; 285 1.63 hannken } 286 1.63 hannken } 287 1.1 gwr 288 1.60 dyoung dk = &sc->sc_dkdev; 289 1.60 dyoung 290 1.1 gwr /* 291 1.21 tsutsui * The raw partition is used for ioctl to configure. 292 1.1 gwr */ 293 1.60 dyoung if (part == RAW_PART) 294 1.60 dyoung goto ok; 295 1.1 gwr 296 1.11 pk #ifdef MEMORY_DISK_HOOKS 297 1.1 gwr /* Call the open hook to allow loading the device. */ 298 1.67 tsutsui configured = (sc->sc_type != MD_UNCONFIGURED); 299 1.11 pk md_open_hook(unit, &sc->sc_md); 300 1.67 tsutsui /* initialize disklabel if the device is configured in open hook */ 301 1.67 tsutsui if (!configured && sc->sc_type != MD_UNCONFIGURED) 302 1.67 tsutsui md_set_disklabel(sc); 303 1.1 gwr #endif 304 1.1 gwr 305 1.1 gwr /* 306 1.1 gwr * This is a normal, "slave" device, so 307 1.21 tsutsui * enforce initialized. 308 1.1 gwr */ 309 1.63 hannken if (sc->sc_type == MD_UNCONFIGURED) { 310 1.63 hannken mutex_exit(&md_device_lock); 311 1.1 gwr return ENXIO; 312 1.63 hannken } 313 1.1 gwr 314 1.60 dyoung ok: 315 1.60 dyoung /* XXX duplicates code in dk_open(). Call dk_open(), instead? */ 316 1.60 dyoung mutex_enter(&dk->dk_openlock); 317 1.60 dyoung /* Mark our unit as open. */ 318 1.60 dyoung switch (fmt) { 319 1.60 dyoung case S_IFCHR: 320 1.60 dyoung dk->dk_copenmask |= pmask; 321 1.60 dyoung break; 322 1.60 dyoung case S_IFBLK: 323 1.60 dyoung dk->dk_bopenmask |= pmask; 324 1.60 dyoung break; 325 1.60 dyoung } 326 1.60 dyoung 327 1.60 dyoung dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; 328 1.60 dyoung 329 1.60 dyoung mutex_exit(&dk->dk_openlock); 330 1.63 hannken mutex_exit(&md_device_lock); 331 1.1 gwr return 0; 332 1.1 gwr } 333 1.1 gwr 334 1.38 thorpej static int 335 1.47 christos mdclose(dev_t dev, int flag, int fmt, struct lwp *l) 336 1.1 gwr { 337 1.60 dyoung int part = DISKPART(dev); 338 1.60 dyoung int pmask = 1 << part; 339 1.63 hannken int error; 340 1.63 hannken cfdata_t cf; 341 1.60 dyoung struct md_softc *sc; 342 1.60 dyoung struct disk *dk; 343 1.60 dyoung 344 1.60 dyoung sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 345 1.60 dyoung if (sc == NULL) 346 1.60 dyoung return ENXIO; 347 1.60 dyoung 348 1.60 dyoung dk = &sc->sc_dkdev; 349 1.60 dyoung 350 1.60 dyoung mutex_enter(&dk->dk_openlock); 351 1.60 dyoung 352 1.60 dyoung switch (fmt) { 353 1.60 dyoung case S_IFCHR: 354 1.60 dyoung dk->dk_copenmask &= ~pmask; 355 1.60 dyoung break; 356 1.60 dyoung case S_IFBLK: 357 1.60 dyoung dk->dk_bopenmask &= ~pmask; 358 1.60 dyoung break; 359 1.60 dyoung } 360 1.60 dyoung dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; 361 1.68 hannken if (dk->dk_openmask != 0) { 362 1.68 hannken mutex_exit(&dk->dk_openlock); 363 1.68 hannken return 0; 364 1.68 hannken } 365 1.1 gwr 366 1.60 dyoung mutex_exit(&dk->dk_openlock); 367 1.63 hannken 368 1.63 hannken mutex_enter(&md_device_lock); 369 1.63 hannken cf = device_cfdata(sc->sc_dev); 370 1.63 hannken error = config_detach(sc->sc_dev, DETACH_QUIET); 371 1.63 hannken if (! error) 372 1.86 thorpej kmem_free(cf, sizeof(*cf)); 373 1.63 hannken mutex_exit(&md_device_lock); 374 1.63 hannken return error; 375 1.1 gwr } 376 1.1 gwr 377 1.38 thorpej static int 378 1.47 christos mdread(dev_t dev, struct uio *uio, int flags) 379 1.1 gwr { 380 1.21 tsutsui struct md_softc *sc; 381 1.21 tsutsui 382 1.54 cegger sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 383 1.21 tsutsui 384 1.62 dyoung if (sc == NULL || sc->sc_type == MD_UNCONFIGURED) 385 1.21 tsutsui return ENXIO; 386 1.21 tsutsui 387 1.11 pk return (physio(mdstrategy, NULL, dev, B_READ, minphys, uio)); 388 1.1 gwr } 389 1.1 gwr 390 1.38 thorpej static int 391 1.47 christos mdwrite(dev_t dev, struct uio *uio, int flags) 392 1.1 gwr { 393 1.21 tsutsui struct md_softc *sc; 394 1.21 tsutsui 395 1.54 cegger sc = device_lookup_private(&md_cd, MD_UNIT(dev)); 396 1.21 tsutsui 397 1.62 dyoung if (sc == NULL || sc->sc_type == MD_UNCONFIGURED) 398 1.21 tsutsui return ENXIO; 399 1.21 tsutsui 400 1.11 pk return (physio(mdstrategy, NULL, dev, B_WRITE, minphys, uio)); 401 1.1 gwr } 402 1.1 gwr 403 1.1 gwr /* 404 1.1 gwr * Handle I/O requests, either directly, or 405 1.1 gwr * by passing them to the server process. 406 1.1 gwr */ 407 1.38 thorpej static void 408 1.38 thorpej mdstrategy(struct buf *bp) 409 1.1 gwr { 410 1.11 pk struct md_softc *sc; 411 1.48 christos void * addr; 412 1.21 tsutsui size_t off, xfer; 413 1.63 hannken bool is_read; 414 1.1 gwr 415 1.54 cegger sc = device_lookup_private(&md_cd, MD_UNIT(bp->b_dev)); 416 1.1 gwr 417 1.62 dyoung if (sc == NULL || sc->sc_type == MD_UNCONFIGURED) { 418 1.21 tsutsui bp->b_error = ENXIO; 419 1.21 tsutsui goto done; 420 1.21 tsutsui } 421 1.21 tsutsui 422 1.77 pgoyette mutex_enter(&sc->sc_lock); 423 1.77 pgoyette 424 1.1 gwr switch (sc->sc_type) { 425 1.11 pk #if MEMORY_DISK_SERVER 426 1.11 pk case MD_UMEM_SERVER: 427 1.1 gwr /* Just add this job to the server's queue. */ 428 1.57 yamt bufq_put(sc->sc_buflist, bp); 429 1.65 hannken cv_signal(&sc->sc_cv); 430 1.65 hannken mutex_exit(&sc->sc_lock); 431 1.29 hannken /* see md_server_loop() */ 432 1.1 gwr /* no biodone in this case */ 433 1.1 gwr return; 434 1.11 pk #endif /* MEMORY_DISK_SERVER */ 435 1.1 gwr 436 1.11 pk case MD_KMEM_FIXED: 437 1.11 pk case MD_KMEM_ALLOCATED: 438 1.1 gwr /* These are in kernel space. Access directly. */ 439 1.63 hannken is_read = ((bp->b_flags & B_READ) == B_READ); 440 1.1 gwr bp->b_resid = bp->b_bcount; 441 1.1 gwr off = (bp->b_blkno << DEV_BSHIFT); 442 1.1 gwr if (off >= sc->sc_size) { 443 1.63 hannken if (is_read) 444 1.1 gwr break; /* EOF */ 445 1.1 gwr goto set_eio; 446 1.1 gwr } 447 1.1 gwr xfer = bp->b_resid; 448 1.1 gwr if (xfer > (sc->sc_size - off)) 449 1.1 gwr xfer = (sc->sc_size - off); 450 1.48 christos addr = (char *)sc->sc_addr + off; 451 1.63 hannken disk_busy(&sc->sc_dkdev); 452 1.63 hannken if (is_read) 453 1.26 thorpej memcpy(bp->b_data, addr, xfer); 454 1.1 gwr else 455 1.26 thorpej memcpy(addr, bp->b_data, xfer); 456 1.63 hannken disk_unbusy(&sc->sc_dkdev, xfer, is_read); 457 1.1 gwr bp->b_resid -= xfer; 458 1.1 gwr break; 459 1.1 gwr 460 1.1 gwr default: 461 1.1 gwr bp->b_resid = bp->b_bcount; 462 1.1 gwr set_eio: 463 1.1 gwr bp->b_error = EIO; 464 1.1 gwr break; 465 1.1 gwr } 466 1.78 pgoyette mutex_exit(&sc->sc_lock); 467 1.66 hannken 468 1.21 tsutsui done: 469 1.66 hannken 470 1.1 gwr biodone(bp); 471 1.1 gwr } 472 1.1 gwr 473 1.38 thorpej static int 474 1.48 christos mdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 475 1.1 gwr { 476 1.21 tsutsui struct md_softc *sc; 477 1.21 tsutsui struct md_conf *umd; 478 1.65 hannken int error; 479 1.1 gwr 480 1.62 dyoung if ((sc = device_lookup_private(&md_cd, MD_UNIT(dev))) == NULL) 481 1.62 dyoung return ENXIO; 482 1.1 gwr 483 1.63 hannken if (sc->sc_type != MD_UNCONFIGURED) { 484 1.72 christos error = disk_ioctl(&sc->sc_dkdev, dev, cmd, data, flag, l); 485 1.72 christos if (error != EPASSTHROUGH) { 486 1.81 hannken return error; 487 1.63 hannken } 488 1.63 hannken } 489 1.63 hannken 490 1.21 tsutsui /* If this is not the raw partition, punt! */ 491 1.65 hannken if (DISKPART(dev) != RAW_PART) { 492 1.1 gwr return ENOTTY; 493 1.65 hannken } 494 1.1 gwr 495 1.81 hannken mutex_enter(&sc->sc_lock); 496 1.11 pk umd = (struct md_conf *)data; 497 1.65 hannken error = EINVAL; 498 1.1 gwr switch (cmd) { 499 1.11 pk case MD_GETCONF: 500 1.11 pk *umd = sc->sc_md; 501 1.65 hannken error = 0; 502 1.65 hannken break; 503 1.1 gwr 504 1.11 pk case MD_SETCONF: 505 1.1 gwr /* Can only set it once. */ 506 1.11 pk if (sc->sc_type != MD_UNCONFIGURED) 507 1.1 gwr break; 508 1.11 pk switch (umd->md_type) { 509 1.11 pk case MD_KMEM_ALLOCATED: 510 1.65 hannken error = md_ioctl_kalloc(sc, umd, l); 511 1.65 hannken break; 512 1.11 pk #if MEMORY_DISK_SERVER 513 1.11 pk case MD_UMEM_SERVER: 514 1.65 hannken error = md_ioctl_server(sc, umd, l); 515 1.65 hannken break; 516 1.33 atatat #endif /* MEMORY_DISK_SERVER */ 517 1.1 gwr default: 518 1.1 gwr break; 519 1.1 gwr } 520 1.1 gwr break; 521 1.1 gwr } 522 1.65 hannken mutex_exit(&sc->sc_lock); 523 1.65 hannken return error; 524 1.1 gwr } 525 1.1 gwr 526 1.63 hannken static void 527 1.63 hannken md_set_disklabel(struct md_softc *sc) 528 1.63 hannken { 529 1.76 hannken struct disk_geom *dg = &sc->sc_dkdev.dk_geom; 530 1.63 hannken struct disklabel *lp = sc->sc_dkdev.dk_label; 531 1.63 hannken struct partition *pp; 532 1.63 hannken 533 1.63 hannken memset(lp, 0, sizeof(*lp)); 534 1.63 hannken 535 1.63 hannken lp->d_secsize = DEV_BSIZE; 536 1.63 hannken lp->d_secperunit = sc->sc_size / DEV_BSIZE; 537 1.63 hannken if (lp->d_secperunit >= (32*64)) { 538 1.63 hannken lp->d_nsectors = 32; 539 1.63 hannken lp->d_ntracks = 64; 540 1.63 hannken lp->d_ncylinders = lp->d_secperunit / (32*64); 541 1.63 hannken } else { 542 1.63 hannken lp->d_nsectors = 1; 543 1.63 hannken lp->d_ntracks = 1; 544 1.63 hannken lp->d_ncylinders = lp->d_secperunit; 545 1.63 hannken } 546 1.63 hannken lp->d_secpercyl = lp->d_ntracks*lp->d_nsectors; 547 1.63 hannken 548 1.63 hannken strncpy(lp->d_typename, md_cd.cd_name, sizeof(lp->d_typename)); 549 1.73 christos lp->d_type = DKTYPE_MD; 550 1.63 hannken strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 551 1.63 hannken lp->d_rpm = 3600; 552 1.63 hannken lp->d_interleave = 1; 553 1.63 hannken lp->d_flags = 0; 554 1.63 hannken 555 1.63 hannken pp = &lp->d_partitions[0]; 556 1.63 hannken pp->p_offset = 0; 557 1.63 hannken pp->p_size = lp->d_secperunit; 558 1.63 hannken pp->p_fstype = FS_BSDFFS; 559 1.63 hannken 560 1.63 hannken pp = &lp->d_partitions[RAW_PART]; 561 1.63 hannken pp->p_offset = 0; 562 1.63 hannken pp->p_size = lp->d_secperunit; 563 1.63 hannken pp->p_fstype = FS_UNUSED; 564 1.63 hannken 565 1.63 hannken lp->d_npartitions = RAW_PART+1; 566 1.63 hannken lp->d_magic = DISKMAGIC; 567 1.63 hannken lp->d_magic2 = DISKMAGIC; 568 1.63 hannken lp->d_checksum = dkcksum(lp); 569 1.76 hannken 570 1.76 hannken memset(dg, 0, sizeof(*dg)); 571 1.76 hannken 572 1.76 hannken dg->dg_secsize = lp->d_secsize; 573 1.76 hannken dg->dg_secperunit = lp->d_secperunit; 574 1.76 hannken dg->dg_nsectors = lp->d_nsectors; 575 1.85 msaitoh dg->dg_ntracks = lp->d_ntracks = 64; 576 1.76 hannken dg->dg_ncylinders = lp->d_ncylinders; 577 1.76 hannken 578 1.76 hannken disk_set_info(sc->sc_dev, &sc->sc_dkdev, NULL); 579 1.63 hannken } 580 1.63 hannken 581 1.1 gwr /* 582 1.11 pk * Handle ioctl MD_SETCONF for (sc_type == MD_KMEM_ALLOCATED) 583 1.1 gwr * Just allocate some kernel memory and return. 584 1.1 gwr */ 585 1.8 leo static int 586 1.46 christos md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd, 587 1.47 christos struct lwp *l) 588 1.1 gwr { 589 1.17 eeh vaddr_t addr; 590 1.21 tsutsui vsize_t size; 591 1.1 gwr 592 1.87 hannken /* Sanity check the size. */ 593 1.87 hannken size = umd->md_size; 594 1.87 hannken if (size < DEV_BSIZE || (size % DEV_BSIZE) != 0) 595 1.87 hannken return EINVAL; 596 1.87 hannken 597 1.66 hannken mutex_exit(&sc->sc_lock); 598 1.65 hannken 599 1.41 yamt addr = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_WIRED|UVM_KMF_ZERO); 600 1.66 hannken 601 1.66 hannken mutex_enter(&sc->sc_lock); 602 1.66 hannken 603 1.1 gwr if (!addr) 604 1.1 gwr return ENOMEM; 605 1.1 gwr 606 1.66 hannken /* If another thread beat us to configure this unit: fail. */ 607 1.66 hannken if (sc->sc_type != MD_UNCONFIGURED) { 608 1.66 hannken uvm_km_free(kernel_map, addr, size, UVM_KMF_WIRED); 609 1.66 hannken return EINVAL; 610 1.66 hannken } 611 1.66 hannken 612 1.1 gwr /* This unit is now configured. */ 613 1.48 christos sc->sc_addr = (void *)addr; /* kernel space */ 614 1.1 gwr sc->sc_size = (size_t)size; 615 1.11 pk sc->sc_type = MD_KMEM_ALLOCATED; 616 1.63 hannken md_set_disklabel(sc); 617 1.1 gwr return 0; 618 1.40 perry } 619 1.1 gwr 620 1.11 pk #if MEMORY_DISK_SERVER 621 1.1 gwr 622 1.1 gwr /* 623 1.11 pk * Handle ioctl MD_SETCONF for (sc_type == MD_UMEM_SERVER) 624 1.1 gwr * Set config, then become the I/O server for this unit. 625 1.1 gwr */ 626 1.8 leo static int 627 1.46 christos md_ioctl_server(struct md_softc *sc, struct md_conf *umd, 628 1.47 christos struct lwp *l) 629 1.1 gwr { 630 1.17 eeh vaddr_t end; 631 1.1 gwr int error; 632 1.1 gwr 633 1.65 hannken KASSERT(mutex_owned(&sc->sc_lock)); 634 1.65 hannken 635 1.1 gwr /* Sanity check addr, size. */ 636 1.48 christos end = (vaddr_t) ((char *)umd->md_addr + umd->md_size); 637 1.1 gwr 638 1.80 christos if ( 639 1.80 christos #ifndef _RUMPKERNEL 640 1.80 christos /* 641 1.80 christos * On some architectures (e.g. powerpc) rump kernel provides 642 1.80 christos * "safe" low defaults which make this test fail since malloc 643 1.80 christos * does return higher addresses than the "safe" default. 644 1.80 christos */ 645 1.80 christos (end >= VM_MAXUSER_ADDRESS) || 646 1.80 christos #endif 647 1.80 christos (end < ((vaddr_t) umd->md_addr))) 648 1.1 gwr return EINVAL; 649 1.1 gwr 650 1.1 gwr /* This unit is now configured. */ 651 1.11 pk sc->sc_addr = umd->md_addr; /* user space */ 652 1.11 pk sc->sc_size = umd->md_size; 653 1.11 pk sc->sc_type = MD_UMEM_SERVER; 654 1.63 hannken md_set_disklabel(sc); 655 1.1 gwr 656 1.1 gwr /* Become the server daemon */ 657 1.11 pk error = md_server_loop(sc); 658 1.1 gwr 659 1.1 gwr /* This server is now going away! */ 660 1.11 pk sc->sc_type = MD_UNCONFIGURED; 661 1.1 gwr sc->sc_addr = 0; 662 1.1 gwr sc->sc_size = 0; 663 1.1 gwr 664 1.1 gwr return (error); 665 1.40 perry } 666 1.1 gwr 667 1.1 gwr static int 668 1.38 thorpej md_server_loop(struct md_softc *sc) 669 1.1 gwr { 670 1.1 gwr struct buf *bp; 671 1.48 christos void *addr; /* user space address */ 672 1.21 tsutsui size_t off; /* offset into "device" */ 673 1.21 tsutsui size_t xfer; /* amount to transfer */ 674 1.1 gwr int error; 675 1.63 hannken bool is_read; 676 1.1 gwr 677 1.65 hannken KASSERT(mutex_owned(&sc->sc_lock)); 678 1.65 hannken 679 1.1 gwr for (;;) { 680 1.1 gwr /* Wait for some work to arrive. */ 681 1.57 yamt while ((bp = bufq_get(sc->sc_buflist)) == NULL) { 682 1.65 hannken error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); 683 1.1 gwr if (error) 684 1.1 gwr return error; 685 1.1 gwr } 686 1.1 gwr 687 1.1 gwr /* Do the transfer to/from user space. */ 688 1.65 hannken mutex_exit(&sc->sc_lock); 689 1.1 gwr error = 0; 690 1.63 hannken is_read = ((bp->b_flags & B_READ) == B_READ); 691 1.1 gwr bp->b_resid = bp->b_bcount; 692 1.1 gwr off = (bp->b_blkno << DEV_BSHIFT); 693 1.1 gwr if (off >= sc->sc_size) { 694 1.63 hannken if (is_read) 695 1.1 gwr goto done; /* EOF (not an error) */ 696 1.1 gwr error = EIO; 697 1.1 gwr goto done; 698 1.1 gwr } 699 1.1 gwr xfer = bp->b_resid; 700 1.1 gwr if (xfer > (sc->sc_size - off)) 701 1.1 gwr xfer = (sc->sc_size - off); 702 1.48 christos addr = (char *)sc->sc_addr + off; 703 1.63 hannken disk_busy(&sc->sc_dkdev); 704 1.63 hannken if (is_read) 705 1.1 gwr error = copyin(addr, bp->b_data, xfer); 706 1.1 gwr else 707 1.1 gwr error = copyout(bp->b_data, addr, xfer); 708 1.63 hannken disk_unbusy(&sc->sc_dkdev, (error ? 0 : xfer), is_read); 709 1.1 gwr if (!error) 710 1.1 gwr bp->b_resid -= xfer; 711 1.1 gwr 712 1.1 gwr done: 713 1.1 gwr if (error) { 714 1.1 gwr bp->b_error = error; 715 1.1 gwr } 716 1.1 gwr biodone(bp); 717 1.65 hannken mutex_enter(&sc->sc_lock); 718 1.1 gwr } 719 1.1 gwr } 720 1.11 pk #endif /* MEMORY_DISK_SERVER */ 721