1139749Simp/*- 294749Sbenno * Copyright (C) 2002 Benno Rice <benno@FreeBSD.org> 394749Sbenno * All rights reserved. 494749Sbenno * 594749Sbenno * Redistribution and use in source and binary forms, with or without 694749Sbenno * modification, are permitted provided that the following conditions 794749Sbenno * are met: 894749Sbenno * 1. Redistributions of source code must retain the above copyright 994749Sbenno * notice, this list of conditions and the following disclaimer. 1094749Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1194749Sbenno * notice, this list of conditions and the following disclaimer in the 1294749Sbenno * documentation and/or other materials provided with the distribution. 1394749Sbenno * 1494749Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 1594749Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1694749Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1794749Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1894749Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1994749Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2094749Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2194749Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2294749Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2394749Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2494749Sbenno */ 2594749Sbenno 26119418Sobrien#include <sys/cdefs.h> 27119418Sobrien__FBSDID("$FreeBSD$"); 28119418Sobrien 2994749Sbenno#include <sys/param.h> 3094749Sbenno#include <sys/systm.h> 3194749Sbenno#include <sys/bio.h> 3294749Sbenno#include <sys/kernel.h> 33139100Sgrehan#include <sys/kthread.h> 34139100Sgrehan#include <sys/linker.h> 35139100Sgrehan#include <sys/lock.h> 36139100Sgrehan#include <sys/malloc.h> 37139100Sgrehan#include <sys/mutex.h> 38139100Sgrehan#include <sys/proc.h> 3994749Sbenno 40139100Sgrehan#include <geom/geom.h> 41139100Sgrehan 4294749Sbenno#include <dev/ofw/openfirm.h> 4394749Sbenno 4494749Sbenno#define OFWD_BLOCKSIZE 512 4594749Sbenno 4694749Sbennostruct ofwd_softc 4794749Sbenno{ 48194138Smarius struct bio_queue_head ofwd_bio_queue; 49194138Smarius struct mtx ofwd_queue_mtx; 5094749Sbenno ihandle_t ofwd_instance; 51139100Sgrehan off_t ofwd_mediasize; 52194138Smarius unsigned ofwd_sectorsize; 53194138Smarius unsigned ofwd_fwheads; 54194138Smarius unsigned ofwd_fwsectors; 55194138Smarius struct proc *ofwd_procp; 56194138Smarius struct g_geom *ofwd_gp; 57194138Smarius struct g_provider *ofwd_pp; 58139100Sgrehan} ofwd_softc; 5994749Sbenno 60139100Sgrehanstatic g_init_t g_ofwd_init; 61139100Sgrehanstatic g_start_t g_ofwd_start; 62139100Sgrehanstatic g_access_t g_ofwd_access; 6394749Sbenno 64139100Sgrehanstruct g_class g_ofwd_class = { 65139100Sgrehan .name = "OFWD", 66139100Sgrehan .version = G_VERSION, 67139100Sgrehan .init = g_ofwd_init, 68139100Sgrehan .start = g_ofwd_start, 69139100Sgrehan .access = g_ofwd_access, 7094749Sbenno}; 7194749Sbenno 72139100SgrehanDECLARE_GEOM_CLASS(g_ofwd_class, g_ofwd); 7394749Sbenno 74139372Sgrehanstatic int ofwd_enable = 0; 75139372SgrehanTUNABLE_INT("kern.ofw.disk", &ofwd_enable); 76139372Sgrehan 77139100Sgrehanstatic int 78139100Sgrehanofwd_startio(struct ofwd_softc *sc, struct bio *bp) 79139100Sgrehan{ 80139100Sgrehan u_int r; 8194749Sbenno 82139100Sgrehan r = OF_seek(sc->ofwd_instance, bp->bio_offset); 83151894Sgrehan 84194138Smarius switch (bp->bio_cmd) { 85194138Smarius case BIO_READ: 86139100Sgrehan r = OF_read(sc->ofwd_instance, (void *)bp->bio_data, 87194139Smarius bp->bio_length); 88194138Smarius break; 89194138Smarius case BIO_WRITE: 90139100Sgrehan r = OF_write(sc->ofwd_instance, (void *)bp->bio_data, 91194139Smarius bp->bio_length); 92194138Smarius break; 93194138Smarius } 94139100Sgrehan if (r != bp->bio_length) 95139100Sgrehan panic("ofwd: incorrect i/o count"); 9694749Sbenno 97194138Smarius bp->bio_resid = 0; 98194138Smarius return (0); 99139100Sgrehan} 10094749Sbenno 10194749Sbennostatic void 102139100Sgrehanofwd_kthread(void *arg) 10394749Sbenno{ 104139100Sgrehan struct ofwd_softc *sc; 105139100Sgrehan struct bio *bp; 106139100Sgrehan int error; 10794749Sbenno 108194138Smarius sc = arg; 109194138Smarius curthread->td_base_pri = PRIBIO; 11094749Sbenno 111194138Smarius for (;;) { 112139100Sgrehan mtx_lock(&sc->ofwd_queue_mtx); 113139100Sgrehan bp = bioq_takefirst(&sc->ofwd_bio_queue); 114139100Sgrehan if (!bp) { 115139100Sgrehan msleep(sc, &sc->ofwd_queue_mtx, PRIBIO | PDROP, 116139100Sgrehan "ofwdwait", 0); 117194138Smarius continue; 118139100Sgrehan } 119194138Smarius mtx_unlock(&sc->ofwd_queue_mtx); 120194138Smarius if (bp->bio_cmd == BIO_GETATTR) { 121139100Sgrehan error = EOPNOTSUPP; 122194138Smarius } else 123139100Sgrehan error = ofwd_startio(sc, bp); 12494749Sbenno 125139100Sgrehan if (error != -1) { 126194138Smarius bp->bio_completed = bp->bio_length; 127194138Smarius g_io_deliver(bp, error); 128194138Smarius } 12994749Sbenno } 13094749Sbenno} 13194749Sbenno 132125435Sgrehanstatic void 133139100Sgrehang_ofwd_init(struct g_class *mp __unused) 134125435Sgrehan{ 135194138Smarius char path[128]; 136194138Smarius char fname[32]; 137194138Smarius phandle_t ofd; 138139100Sgrehan struct ofwd_softc *sc; 139194138Smarius struct g_geom *gp; 140194138Smarius struct g_provider *pp; 141139100Sgrehan ihandle_t ifd; 142194138Smarius int error; 143125435Sgrehan 144139372Sgrehan if (ofwd_enable == 0) 145139372Sgrehan return; 146139372Sgrehan 147125435Sgrehan ofd = OF_finddevice("ofwdisk"); 148125435Sgrehan if (ofd == -1) 149125435Sgrehan return; 150125435Sgrehan 151139100Sgrehan bzero(path, 128); 152139100Sgrehan OF_package_to_path(ofd, path, 128); 153139100Sgrehan OF_getprop(ofd, "file", fname, sizeof(fname)); 154139100Sgrehan printf("ofw_disk located at %s, file %s\n", path, fname); 155139100Sgrehan ifd = OF_open(path); 156139100Sgrehan if (ifd == -1) { 157139100Sgrehan printf("ofw_disk: could not create instance\n"); 158139100Sgrehan return; 159139100Sgrehan } 160125435Sgrehan 161139100Sgrehan sc = (struct ofwd_softc *)malloc(sizeof *sc, M_DEVBUF, 162194139Smarius M_WAITOK | M_ZERO); 163139100Sgrehan bioq_init(&sc->ofwd_bio_queue); 164194138Smarius mtx_init(&sc->ofwd_queue_mtx, "ofwd bio queue", NULL, MTX_DEF); 165139100Sgrehan sc->ofwd_instance = ifd; 166194138Smarius sc->ofwd_mediasize = (off_t)2 * 33554432; 167139100Sgrehan sc->ofwd_sectorsize = OFWD_BLOCKSIZE; 168139100Sgrehan sc->ofwd_fwsectors = 0; 169139100Sgrehan sc->ofwd_fwheads = 0; 170172836Sjulian error = kproc_create(ofwd_kthread, sc, &sc->ofwd_procp, 0, 0, 171194138Smarius "ofwd0"); 172194138Smarius if (error != 0) { 173139100Sgrehan free(sc, M_DEVBUF); 174194138Smarius return; 175125435Sgrehan } 176139100Sgrehan 177139100Sgrehan gp = g_new_geomf(&g_ofwd_class, "ofwd0"); 178139100Sgrehan gp->softc = sc; 179139100Sgrehan pp = g_new_providerf(gp, "ofwd0"); 180139100Sgrehan pp->mediasize = sc->ofwd_mediasize; 181139100Sgrehan pp->sectorsize = sc->ofwd_sectorsize; 182139100Sgrehan sc->ofwd_gp = gp; 183139100Sgrehan sc->ofwd_pp = pp; 184139100Sgrehan g_error_provider(pp, 0); 185125435Sgrehan} 186125435Sgrehan 187139100Sgrehanstatic void 188139100Sgrehang_ofwd_start(struct bio *bp) 18994749Sbenno{ 190194138Smarius struct ofwd_softc *sc; 19194749Sbenno 192194138Smarius sc = bp->bio_to->geom->softc; 193194138Smarius mtx_lock(&sc->ofwd_queue_mtx); 194194138Smarius bioq_disksort(&sc->ofwd_bio_queue, bp); 195194138Smarius mtx_unlock(&sc->ofwd_queue_mtx); 196194138Smarius wakeup(sc); 19794749Sbenno} 19894749Sbenno 19994749Sbennostatic int 200139100Sgrehang_ofwd_access(struct g_provider *pp, int r, int w, int e) 20194749Sbenno{ 20294749Sbenno 203139100Sgrehan if (pp->geom->softc == NULL) 20494749Sbenno return (ENXIO); 205194138Smarius return (0); 20694749Sbenno} 207