ofw_disk.c revision 151894
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 * 2694749Sbenno */ 2794749Sbenno 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/ofw/ofw_disk.c 151894 2005-10-31 03:09:38Z grehan $"); 30119418Sobrien 3194749Sbenno#include <sys/param.h> 3294749Sbenno#include <sys/systm.h> 3394749Sbenno#include <sys/bio.h> 3494749Sbenno#include <sys/kernel.h> 35139100Sgrehan#include <sys/kthread.h> 36139100Sgrehan#include <sys/linker.h> 37139100Sgrehan#include <sys/lock.h> 38139100Sgrehan#include <sys/malloc.h> 39139100Sgrehan#include <sys/mutex.h> 40139100Sgrehan#include <sys/proc.h> 4194749Sbenno 42139100Sgrehan#include <geom/geom.h> 43139100Sgrehan 4494749Sbenno#include <dev/ofw/openfirm.h> 4594749Sbenno 4694749Sbenno#define OFWD_BLOCKSIZE 512 4794749Sbenno 4894749Sbennostruct ofwd_softc 4994749Sbenno{ 50139100Sgrehan struct bio_queue_head ofwd_bio_queue; 51139100Sgrehan struct mtx ofwd_queue_mtx; 5294749Sbenno ihandle_t ofwd_instance; 53139100Sgrehan off_t ofwd_mediasize; 54139100Sgrehan unsigned ofwd_sectorsize; 55139100Sgrehan unsigned ofwd_fwheads; 56139100Sgrehan unsigned ofwd_fwsectors; 57139100Sgrehan struct proc *ofwd_procp; 58139100Sgrehan struct g_geom *ofwd_gp; 59139100Sgrehan struct g_provider *ofwd_pp; 60139100Sgrehan} ofwd_softc; 6194749Sbenno 62139100Sgrehanstatic g_init_t g_ofwd_init; 63139100Sgrehanstatic g_start_t g_ofwd_start; 64139100Sgrehanstatic g_access_t g_ofwd_access; 6594749Sbenno 66139100Sgrehanstruct g_class g_ofwd_class = { 67139100Sgrehan .name = "OFWD", 68139100Sgrehan .version = G_VERSION, 69139100Sgrehan .init = g_ofwd_init, 70139100Sgrehan .start = g_ofwd_start, 71139100Sgrehan .access = g_ofwd_access, 7294749Sbenno}; 7394749Sbenno 74139100SgrehanDECLARE_GEOM_CLASS(g_ofwd_class, g_ofwd); 7594749Sbenno 76139372Sgrehanstatic int ofwd_enable = 0; 77139372SgrehanTUNABLE_INT("kern.ofw.disk", &ofwd_enable); 78139372Sgrehan 79139100Sgrehanstatic int 80139100Sgrehanofwd_startio(struct ofwd_softc *sc, struct bio *bp) 81139100Sgrehan{ 82139100Sgrehan u_int r; 8394749Sbenno 84139100Sgrehan r = OF_seek(sc->ofwd_instance, bp->bio_offset); 85151894Sgrehan 86139100Sgrehan switch (bp->bio_cmd) { 87139100Sgrehan case BIO_READ: 88139100Sgrehan r = OF_read(sc->ofwd_instance, (void *)bp->bio_data, 89139100Sgrehan bp->bio_length); 90139100Sgrehan break; 91139100Sgrehan case BIO_WRITE: 92139100Sgrehan r = OF_write(sc->ofwd_instance, (void *)bp->bio_data, 93139100Sgrehan bp->bio_length); 94139100Sgrehan break; 95139100Sgrehan } 96139100Sgrehan if (r != bp->bio_length) 97139100Sgrehan panic("ofwd: incorrect i/o count"); 9894749Sbenno 99139100Sgrehan bp->bio_resid = 0; 100139100Sgrehan return (0); 101139100Sgrehan} 10294749Sbenno 10394749Sbennostatic void 104139100Sgrehanofwd_kthread(void *arg) 10594749Sbenno{ 106139100Sgrehan struct ofwd_softc *sc; 107139100Sgrehan struct bio *bp; 108139100Sgrehan int error; 10994749Sbenno 110139100Sgrehan sc = arg; 111139100Sgrehan curthread->td_base_pri = PRIBIO; 11294749Sbenno 113139100Sgrehan for (;;) { 114139100Sgrehan mtx_lock(&sc->ofwd_queue_mtx); 115139100Sgrehan bp = bioq_takefirst(&sc->ofwd_bio_queue); 116139100Sgrehan if (!bp) { 117139100Sgrehan msleep(sc, &sc->ofwd_queue_mtx, PRIBIO | PDROP, 118139100Sgrehan "ofwdwait", 0); 119139100Sgrehan continue; 120139100Sgrehan } 121139100Sgrehan mtx_unlock(&sc->ofwd_queue_mtx); 122139100Sgrehan if (bp->bio_cmd == BIO_GETATTR) { 123139100Sgrehan error = EOPNOTSUPP; 124139100Sgrehan } else 125139100Sgrehan error = ofwd_startio(sc, bp); 12694749Sbenno 127139100Sgrehan if (error != -1) { 128139100Sgrehan bp->bio_completed = bp->bio_length; 129139100Sgrehan g_io_deliver(bp, error); 130139100Sgrehan } 13194749Sbenno } 13294749Sbenno} 13394749Sbenno 134125435Sgrehanstatic void 135139100Sgrehang_ofwd_init(struct g_class *mp __unused) 136125435Sgrehan{ 137139100Sgrehan struct ofwd_softc *sc; 138139100Sgrehan struct g_geom *gp; 139139100Sgrehan struct g_provider *pp; 140139100Sgrehan char path[128]; 141139100Sgrehan char fname[32]; 142125435Sgrehan phandle_t ofd; 143139100Sgrehan ihandle_t ifd; 144139100Sgrehan int error; 145125435Sgrehan 146139372Sgrehan if (ofwd_enable == 0) 147139372Sgrehan return; 148139372Sgrehan 149125435Sgrehan ofd = OF_finddevice("ofwdisk"); 150125435Sgrehan if (ofd == -1) 151125435Sgrehan return; 152125435Sgrehan 153139100Sgrehan bzero(path, 128); 154139100Sgrehan OF_package_to_path(ofd, path, 128); 155139100Sgrehan OF_getprop(ofd, "file", fname, sizeof(fname)); 156139100Sgrehan printf("ofw_disk located at %s, file %s\n", path, fname); 157139100Sgrehan ifd = OF_open(path); 158139100Sgrehan if (ifd == -1) { 159139100Sgrehan printf("ofw_disk: could not create instance\n"); 160139100Sgrehan return; 161139100Sgrehan } 162125435Sgrehan 163139100Sgrehan sc = (struct ofwd_softc *)malloc(sizeof *sc, M_DEVBUF, 164139100Sgrehan M_WAITOK|M_ZERO); 165139100Sgrehan bioq_init(&sc->ofwd_bio_queue); 166139100Sgrehan mtx_init(&sc->ofwd_queue_mtx, "ofwd bio queue", NULL, MTX_DEF); 167139100Sgrehan sc->ofwd_instance = ifd; 168151894Sgrehan sc->ofwd_mediasize = (off_t)2*33554432; 169139100Sgrehan sc->ofwd_sectorsize = OFWD_BLOCKSIZE; 170139100Sgrehan sc->ofwd_fwsectors = 0; 171139100Sgrehan sc->ofwd_fwheads = 0; 172139100Sgrehan error = kthread_create(ofwd_kthread, sc, &sc->ofwd_procp, 0, 0, 173139100Sgrehan "ofwd0"); 174139100Sgrehan if (error != 0) { 175139100Sgrehan free(sc, M_DEVBUF); 176139100Sgrehan return; 177125435Sgrehan } 178139100Sgrehan 179139100Sgrehan gp = g_new_geomf(&g_ofwd_class, "ofwd0"); 180139100Sgrehan gp->softc = sc; 181139100Sgrehan pp = g_new_providerf(gp, "ofwd0"); 182139100Sgrehan pp->mediasize = sc->ofwd_mediasize; 183139100Sgrehan pp->sectorsize = sc->ofwd_sectorsize; 184139100Sgrehan sc->ofwd_gp = gp; 185139100Sgrehan sc->ofwd_pp = pp; 186139100Sgrehan g_error_provider(pp, 0); 187125435Sgrehan} 188125435Sgrehan 189139100Sgrehanstatic void 190139100Sgrehang_ofwd_start(struct bio *bp) 19194749Sbenno{ 192139100Sgrehan struct ofwd_softc *sc; 19394749Sbenno 194139100Sgrehan sc = bp->bio_to->geom->softc; 195139100Sgrehan mtx_lock(&sc->ofwd_queue_mtx); 196139100Sgrehan bioq_disksort(&sc->ofwd_bio_queue, bp); 197139100Sgrehan mtx_unlock(&sc->ofwd_queue_mtx); 198139100Sgrehan wakeup(sc); 19994749Sbenno} 20094749Sbenno 20194749Sbennostatic int 202139100Sgrehang_ofwd_access(struct g_provider *pp, int r, int w, int e) 20394749Sbenno{ 20494749Sbenno 205139100Sgrehan if (pp->geom->softc == NULL) 20694749Sbenno return (ENXIO); 207139100Sgrehan return (0); 20894749Sbenno} 209