1098ca2bdSWarner Losh /*- 2d9611800SBenno Rice * Copyright (C) 2002 Benno Rice <benno@FreeBSD.org> 3d9611800SBenno Rice * All rights reserved. 4d9611800SBenno Rice * 5d9611800SBenno Rice * Redistribution and use in source and binary forms, with or without 6d9611800SBenno Rice * modification, are permitted provided that the following conditions 7d9611800SBenno Rice * are met: 8d9611800SBenno Rice * 1. Redistributions of source code must retain the above copyright 9d9611800SBenno Rice * notice, this list of conditions and the following disclaimer. 10d9611800SBenno Rice * 2. Redistributions in binary form must reproduce the above copyright 11d9611800SBenno Rice * notice, this list of conditions and the following disclaimer in the 12d9611800SBenno Rice * documentation and/or other materials provided with the distribution. 13d9611800SBenno Rice * 14d9611800SBenno Rice * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15d9611800SBenno Rice * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16d9611800SBenno Rice * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17d9611800SBenno Rice * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18d9611800SBenno Rice * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19d9611800SBenno Rice * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20d9611800SBenno Rice * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21d9611800SBenno Rice * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22d9611800SBenno Rice * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23d9611800SBenno Rice * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24d9611800SBenno Rice * 25d9611800SBenno Rice * 26d9611800SBenno Rice */ 27d9611800SBenno Rice 28aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 29aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 30aad970f1SDavid E. O'Brien 31d9611800SBenno Rice #include <sys/param.h> 32d9611800SBenno Rice #include <sys/systm.h> 33d9611800SBenno Rice #include <sys/bio.h> 34d9611800SBenno Rice #include <sys/kernel.h> 35d626a8a2SPeter Grehan #include <sys/kthread.h> 36d626a8a2SPeter Grehan #include <sys/linker.h> 37d626a8a2SPeter Grehan #include <sys/lock.h> 38d626a8a2SPeter Grehan #include <sys/malloc.h> 39d626a8a2SPeter Grehan #include <sys/mutex.h> 40d626a8a2SPeter Grehan #include <sys/proc.h> 41d626a8a2SPeter Grehan 42d626a8a2SPeter Grehan #include <geom/geom.h> 43d9611800SBenno Rice 44d9611800SBenno Rice #include <dev/ofw/openfirm.h> 45d9611800SBenno Rice 46d9611800SBenno Rice #define OFWD_BLOCKSIZE 512 47d9611800SBenno Rice 48d9611800SBenno Rice struct ofwd_softc 49d9611800SBenno Rice { 50d626a8a2SPeter Grehan struct bio_queue_head ofwd_bio_queue; 51d626a8a2SPeter Grehan struct mtx ofwd_queue_mtx; 52d9611800SBenno Rice ihandle_t ofwd_instance; 53d626a8a2SPeter Grehan off_t ofwd_mediasize; 54d626a8a2SPeter Grehan unsigned ofwd_sectorsize; 55d626a8a2SPeter Grehan unsigned ofwd_fwheads; 56d626a8a2SPeter Grehan unsigned ofwd_fwsectors; 57d626a8a2SPeter Grehan struct proc *ofwd_procp; 58d626a8a2SPeter Grehan struct g_geom *ofwd_gp; 59d626a8a2SPeter Grehan struct g_provider *ofwd_pp; 60d626a8a2SPeter Grehan } ofwd_softc; 61d626a8a2SPeter Grehan 62d626a8a2SPeter Grehan static g_init_t g_ofwd_init; 63d626a8a2SPeter Grehan static g_start_t g_ofwd_start; 64d626a8a2SPeter Grehan static g_access_t g_ofwd_access; 65d626a8a2SPeter Grehan 66d626a8a2SPeter Grehan struct g_class g_ofwd_class = { 67d626a8a2SPeter Grehan .name = "OFWD", 68d626a8a2SPeter Grehan .version = G_VERSION, 69d626a8a2SPeter Grehan .init = g_ofwd_init, 70d626a8a2SPeter Grehan .start = g_ofwd_start, 71d626a8a2SPeter Grehan .access = g_ofwd_access, 72d9611800SBenno Rice }; 73d9611800SBenno Rice 74d626a8a2SPeter Grehan DECLARE_GEOM_CLASS(g_ofwd_class, g_ofwd); 75d9611800SBenno Rice 76b8e106eaSPeter Grehan static int ofwd_enable = 0; 77b8e106eaSPeter Grehan TUNABLE_INT("kern.ofw.disk", &ofwd_enable); 78b8e106eaSPeter Grehan 79d626a8a2SPeter Grehan static int 80d626a8a2SPeter Grehan ofwd_startio(struct ofwd_softc *sc, struct bio *bp) 81d9611800SBenno Rice { 82d626a8a2SPeter Grehan u_int r; 83aa77148dSPeter Grehan 8424730dd7SPoul-Henning Kamp r = OF_seek(sc->ofwd_instance, bp->bio_offset); 85d626a8a2SPeter Grehan switch (bp->bio_cmd) { 86d626a8a2SPeter Grehan case BIO_READ: 87d9611800SBenno Rice r = OF_read(sc->ofwd_instance, (void *)bp->bio_data, 88d626a8a2SPeter Grehan bp->bio_length); 89d626a8a2SPeter Grehan break; 90d626a8a2SPeter Grehan case BIO_WRITE: 91d9611800SBenno Rice r = OF_write(sc->ofwd_instance, (void *)bp->bio_data, 92d626a8a2SPeter Grehan bp->bio_length); 93d626a8a2SPeter Grehan break; 94d626a8a2SPeter Grehan } 95d626a8a2SPeter Grehan if (r != bp->bio_length) 96d626a8a2SPeter Grehan panic("ofwd: incorrect i/o count"); 97d626a8a2SPeter Grehan 98d626a8a2SPeter Grehan bp->bio_resid = 0; 99d626a8a2SPeter Grehan return (0); 100d9611800SBenno Rice } 101d9611800SBenno Rice 1021ac37de6SPeter Grehan static void 103d626a8a2SPeter Grehan ofwd_kthread(void *arg) 1041ac37de6SPeter Grehan { 105d626a8a2SPeter Grehan struct ofwd_softc *sc; 106d626a8a2SPeter Grehan struct bio *bp; 107d626a8a2SPeter Grehan int error; 108d626a8a2SPeter Grehan 109d626a8a2SPeter Grehan sc = arg; 110d626a8a2SPeter Grehan curthread->td_base_pri = PRIBIO; 111d626a8a2SPeter Grehan 112d626a8a2SPeter Grehan for (;;) { 113d626a8a2SPeter Grehan mtx_lock(&sc->ofwd_queue_mtx); 114d626a8a2SPeter Grehan bp = bioq_takefirst(&sc->ofwd_bio_queue); 115d626a8a2SPeter Grehan if (!bp) { 116d626a8a2SPeter Grehan msleep(sc, &sc->ofwd_queue_mtx, PRIBIO | PDROP, 117d626a8a2SPeter Grehan "ofwdwait", 0); 118d626a8a2SPeter Grehan continue; 119d626a8a2SPeter Grehan } 120d626a8a2SPeter Grehan mtx_unlock(&sc->ofwd_queue_mtx); 121d626a8a2SPeter Grehan if (bp->bio_cmd == BIO_GETATTR) { 122d626a8a2SPeter Grehan error = EOPNOTSUPP; 123d626a8a2SPeter Grehan } else 124d626a8a2SPeter Grehan error = ofwd_startio(sc, bp); 125d626a8a2SPeter Grehan 126d626a8a2SPeter Grehan if (error != -1) { 127d626a8a2SPeter Grehan bp->bio_completed = bp->bio_length; 128d626a8a2SPeter Grehan g_io_deliver(bp, error); 129d626a8a2SPeter Grehan } 130d626a8a2SPeter Grehan } 131d626a8a2SPeter Grehan } 132d626a8a2SPeter Grehan 133d626a8a2SPeter Grehan static void 134d626a8a2SPeter Grehan g_ofwd_init(struct g_class *mp __unused) 135d626a8a2SPeter Grehan { 136d626a8a2SPeter Grehan struct ofwd_softc *sc; 137d626a8a2SPeter Grehan struct g_geom *gp; 138d626a8a2SPeter Grehan struct g_provider *pp; 139d626a8a2SPeter Grehan char path[128]; 140d626a8a2SPeter Grehan char fname[32]; 1411ac37de6SPeter Grehan phandle_t ofd; 142d626a8a2SPeter Grehan ihandle_t ifd; 143d626a8a2SPeter Grehan int error; 1441ac37de6SPeter Grehan 145b8e106eaSPeter Grehan if (ofwd_enable == 0) 146b8e106eaSPeter Grehan return; 147b8e106eaSPeter Grehan 1481ac37de6SPeter Grehan ofd = OF_finddevice("ofwdisk"); 1491ac37de6SPeter Grehan if (ofd == -1) 1501ac37de6SPeter Grehan return; 1511ac37de6SPeter Grehan 152d626a8a2SPeter Grehan bzero(path, 128); 153d626a8a2SPeter Grehan OF_package_to_path(ofd, path, 128); 154d626a8a2SPeter Grehan OF_getprop(ofd, "file", fname, sizeof(fname)); 155d626a8a2SPeter Grehan printf("ofw_disk located at %s, file %s\n", path, fname); 156d626a8a2SPeter Grehan ifd = OF_open(path); 157d626a8a2SPeter Grehan if (ifd == -1) { 158d626a8a2SPeter Grehan printf("ofw_disk: could not create instance\n"); 159d626a8a2SPeter Grehan return; 1601ac37de6SPeter Grehan } 1611ac37de6SPeter Grehan 162d626a8a2SPeter Grehan sc = (struct ofwd_softc *)malloc(sizeof *sc, M_DEVBUF, 163d626a8a2SPeter Grehan M_WAITOK|M_ZERO); 164d626a8a2SPeter Grehan bioq_init(&sc->ofwd_bio_queue); 165d626a8a2SPeter Grehan mtx_init(&sc->ofwd_queue_mtx, "ofwd bio queue", NULL, MTX_DEF); 166d626a8a2SPeter Grehan sc->ofwd_instance = ifd; 167d626a8a2SPeter Grehan sc->ofwd_mediasize = (off_t)2*33554432 * OFWD_BLOCKSIZE; 168d626a8a2SPeter Grehan sc->ofwd_sectorsize = OFWD_BLOCKSIZE; 169d626a8a2SPeter Grehan sc->ofwd_fwsectors = 0; 170d626a8a2SPeter Grehan sc->ofwd_fwheads = 0; 171d626a8a2SPeter Grehan error = kthread_create(ofwd_kthread, sc, &sc->ofwd_procp, 0, 0, 172d626a8a2SPeter Grehan "ofwd0"); 173d626a8a2SPeter Grehan if (error != 0) { 174d626a8a2SPeter Grehan free(sc, M_DEVBUF); 175d626a8a2SPeter Grehan return; 176d9611800SBenno Rice } 177d9611800SBenno Rice 178d626a8a2SPeter Grehan gp = g_new_geomf(&g_ofwd_class, "ofwd0"); 179d626a8a2SPeter Grehan gp->softc = sc; 180d626a8a2SPeter Grehan pp = g_new_providerf(gp, "ofwd0"); 181d626a8a2SPeter Grehan pp->mediasize = sc->ofwd_mediasize; 182d626a8a2SPeter Grehan pp->sectorsize = sc->ofwd_sectorsize; 183d626a8a2SPeter Grehan sc->ofwd_gp = gp; 184d626a8a2SPeter Grehan sc->ofwd_pp = pp; 185d626a8a2SPeter Grehan g_error_provider(pp, 0); 186d626a8a2SPeter Grehan } 187d626a8a2SPeter Grehan 188d626a8a2SPeter Grehan static void 189d626a8a2SPeter Grehan g_ofwd_start(struct bio *bp) 190d9611800SBenno Rice { 191d9611800SBenno Rice struct ofwd_softc *sc; 192d9611800SBenno Rice 193d626a8a2SPeter Grehan sc = bp->bio_to->geom->softc; 194d626a8a2SPeter Grehan mtx_lock(&sc->ofwd_queue_mtx); 195d626a8a2SPeter Grehan bioq_disksort(&sc->ofwd_bio_queue, bp); 196d626a8a2SPeter Grehan mtx_unlock(&sc->ofwd_queue_mtx); 197d626a8a2SPeter Grehan wakeup(sc); 198d9611800SBenno Rice } 199d9611800SBenno Rice 200d626a8a2SPeter Grehan static int 201d626a8a2SPeter Grehan g_ofwd_access(struct g_provider *pp, int r, int w, int e) 202d626a8a2SPeter Grehan { 203d9611800SBenno Rice 204d626a8a2SPeter Grehan if (pp->geom->softc == NULL) 205d626a8a2SPeter Grehan return (ENXIO); 206d9611800SBenno Rice return (0); 207d9611800SBenno Rice } 208