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