ofw_disk.c revision 139372
1223013Sdim/* 2223013Sdim * Copyright (C) 2002 Benno Rice <benno@FreeBSD.org> 3223013Sdim * All rights reserved. 4223013Sdim * 5223013Sdim * Redistribution and use in source and binary forms, with or without 6223013Sdim * modification, are permitted provided that the following conditions 7223013Sdim * are met: 8223013Sdim * 1. Redistributions of source code must retain the above copyright 9223013Sdim * notice, this list of conditions and the following disclaimer. 10223013Sdim * 2. Redistributions in binary form must reproduce the above copyright 11223013Sdim * notice, this list of conditions and the following disclaimer in the 12223013Sdim * documentation and/or other materials provided with the distribution. 13223013Sdim * 14223013Sdim * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15223013Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16223013Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17223013Sdim * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18223013Sdim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19223013Sdim * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20223013Sdim * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21223013Sdim * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22223013Sdim * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23223013Sdim * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24223013Sdim * 25223013Sdim * 26223013Sdim */ 27223013Sdim 28223013Sdim#include <sys/cdefs.h> 29223013Sdim__FBSDID("$FreeBSD: head/sys/dev/ofw/ofw_disk.c 139372 2004-12-28 05:07:49Z grehan $"); 30223013Sdim 31223013Sdim#include <sys/param.h> 32223013Sdim#include <sys/systm.h> 33223013Sdim#include <sys/bio.h> 34223013Sdim#include <sys/kernel.h> 35223013Sdim#include <sys/kthread.h> 36223013Sdim#include <sys/linker.h> 37223013Sdim#include <sys/lock.h> 38223013Sdim#include <sys/malloc.h> 39223013Sdim#include <sys/mutex.h> 40223013Sdim#include <sys/proc.h> 41223013Sdim 42223013Sdim#include <geom/geom.h> 43223013Sdim 44223013Sdim#include <dev/ofw/openfirm.h> 45223013Sdim 46223013Sdim#define OFWD_BLOCKSIZE 512 47223013Sdim 48223013Sdimstruct ofwd_softc 49223013Sdim{ 50223013Sdim struct bio_queue_head ofwd_bio_queue; 51223013Sdim struct mtx ofwd_queue_mtx; 52223013Sdim ihandle_t ofwd_instance; 53223013Sdim off_t ofwd_mediasize; 54223013Sdim unsigned ofwd_sectorsize; 55223013Sdim unsigned ofwd_fwheads; 56223013Sdim unsigned ofwd_fwsectors; 57223013Sdim struct proc *ofwd_procp; 58223013Sdim struct g_geom *ofwd_gp; 59223013Sdim struct g_provider *ofwd_pp; 60223013Sdim} ofwd_softc; 61223013Sdim 62223013Sdimstatic g_init_t g_ofwd_init; 63223013Sdimstatic g_start_t g_ofwd_start; 64223013Sdimstatic g_access_t g_ofwd_access; 65223013Sdim 66223013Sdimstruct g_class g_ofwd_class = { 67223013Sdim .name = "OFWD", 68223013Sdim .version = G_VERSION, 69223013Sdim .init = g_ofwd_init, 70223013Sdim .start = g_ofwd_start, 71223013Sdim .access = g_ofwd_access, 72223013Sdim}; 73223013Sdim 74223013SdimDECLARE_GEOM_CLASS(g_ofwd_class, g_ofwd); 75223013Sdim 76223013Sdimstatic int ofwd_enable = 0; 77223013SdimTUNABLE_INT("kern.ofw.disk", &ofwd_enable); 78223013Sdim 79223013Sdimstatic int 80223013Sdimofwd_startio(struct ofwd_softc *sc, struct bio *bp) 81223013Sdim{ 82223013Sdim u_int r; 83223013Sdim 84224145Sdim r = OF_seek(sc->ofwd_instance, bp->bio_offset); 85224145Sdim switch (bp->bio_cmd) { 86224145Sdim case BIO_READ: 87223013Sdim r = OF_read(sc->ofwd_instance, (void *)bp->bio_data, 88223013Sdim bp->bio_length); 89223013Sdim break; 90223013Sdim case BIO_WRITE: 91223013Sdim r = OF_write(sc->ofwd_instance, (void *)bp->bio_data, 92223013Sdim bp->bio_length); 93223013Sdim break; 94223013Sdim } 95223013Sdim if (r != bp->bio_length) 96223013Sdim panic("ofwd: incorrect i/o count"); 97223013Sdim 98223013Sdim bp->bio_resid = 0; 99223013Sdim return (0); 100223013Sdim} 101223013Sdim 102223013Sdimstatic void 103223013Sdimofwd_kthread(void *arg) 104224145Sdim{ 105223013Sdim struct ofwd_softc *sc; 106223013Sdim struct bio *bp; 107223013Sdim int error; 108223013Sdim 109223013Sdim sc = arg; 110223013Sdim curthread->td_base_pri = PRIBIO; 111223013Sdim 112223013Sdim for (;;) { 113 mtx_lock(&sc->ofwd_queue_mtx); 114 bp = bioq_takefirst(&sc->ofwd_bio_queue); 115 if (!bp) { 116 msleep(sc, &sc->ofwd_queue_mtx, PRIBIO | PDROP, 117 "ofwdwait", 0); 118 continue; 119 } 120 mtx_unlock(&sc->ofwd_queue_mtx); 121 if (bp->bio_cmd == BIO_GETATTR) { 122 error = EOPNOTSUPP; 123 } else 124 error = ofwd_startio(sc, bp); 125 126 if (error != -1) { 127 bp->bio_completed = bp->bio_length; 128 g_io_deliver(bp, error); 129 } 130 } 131} 132 133static void 134g_ofwd_init(struct g_class *mp __unused) 135{ 136 struct ofwd_softc *sc; 137 struct g_geom *gp; 138 struct g_provider *pp; 139 char path[128]; 140 char fname[32]; 141 phandle_t ofd; 142 ihandle_t ifd; 143 int error; 144 145 if (ofwd_enable == 0) 146 return; 147 148 ofd = OF_finddevice("ofwdisk"); 149 if (ofd == -1) 150 return; 151 152 bzero(path, 128); 153 OF_package_to_path(ofd, path, 128); 154 OF_getprop(ofd, "file", fname, sizeof(fname)); 155 printf("ofw_disk located at %s, file %s\n", path, fname); 156 ifd = OF_open(path); 157 if (ifd == -1) { 158 printf("ofw_disk: could not create instance\n"); 159 return; 160 } 161 162 sc = (struct ofwd_softc *)malloc(sizeof *sc, M_DEVBUF, 163 M_WAITOK|M_ZERO); 164 bioq_init(&sc->ofwd_bio_queue); 165 mtx_init(&sc->ofwd_queue_mtx, "ofwd bio queue", NULL, MTX_DEF); 166 sc->ofwd_instance = ifd; 167 sc->ofwd_mediasize = (off_t)2*33554432 * OFWD_BLOCKSIZE; 168 sc->ofwd_sectorsize = OFWD_BLOCKSIZE; 169 sc->ofwd_fwsectors = 0; 170 sc->ofwd_fwheads = 0; 171 error = kthread_create(ofwd_kthread, sc, &sc->ofwd_procp, 0, 0, 172 "ofwd0"); 173 if (error != 0) { 174 free(sc, M_DEVBUF); 175 return; 176 } 177 178 gp = g_new_geomf(&g_ofwd_class, "ofwd0"); 179 gp->softc = sc; 180 pp = g_new_providerf(gp, "ofwd0"); 181 pp->mediasize = sc->ofwd_mediasize; 182 pp->sectorsize = sc->ofwd_sectorsize; 183 sc->ofwd_gp = gp; 184 sc->ofwd_pp = pp; 185 g_error_provider(pp, 0); 186} 187 188static void 189g_ofwd_start(struct bio *bp) 190{ 191 struct ofwd_softc *sc; 192 193 sc = bp->bio_to->geom->softc; 194 mtx_lock(&sc->ofwd_queue_mtx); 195 bioq_disksort(&sc->ofwd_bio_queue, bp); 196 mtx_unlock(&sc->ofwd_queue_mtx); 197 wakeup(sc); 198} 199 200static int 201g_ofwd_access(struct g_provider *pp, int r, int w, int e) 202{ 203 204 if (pp->geom->softc == NULL) 205 return (ENXIO); 206 return (0); 207} 208