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