1139749Simp/*- 265942Sgibbs * Copyright (C) 2002 Benno Rice <benno@FreeBSD.org> 365942Sgibbs * All rights reserved. 471717Sgibbs * 595378Sgibbs * Redistribution and use in source and binary forms, with or without 665942Sgibbs * modification, are permitted provided that the following conditions 765942Sgibbs * are met: 865942Sgibbs * 1. Redistributions of source code must retain the above copyright 965942Sgibbs * notice, this list of conditions and the following disclaimer. 1065942Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1165942Sgibbs * notice, this list of conditions and the following disclaimer in the 1265942Sgibbs * documentation and/or other materials provided with the distribution. 1365942Sgibbs * 1495378Sgibbs * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 1595378Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1695378Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1795378Sgibbs * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1895378Sgibbs * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1995378Sgibbs * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2095378Sgibbs * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2195378Sgibbs * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2265942Sgibbs * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2365942Sgibbs * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2495378Sgibbs */ 2595378Sgibbs 2665942Sgibbs#include <sys/cdefs.h> 2795378Sgibbs__FBSDID("$FreeBSD$"); 2895378Sgibbs 2995378Sgibbs#include <sys/param.h> 3095378Sgibbs#include <sys/systm.h> 3195378Sgibbs#include <sys/bio.h> 3295378Sgibbs#include <sys/kernel.h> 3365942Sgibbs#include <sys/kthread.h> 3465942Sgibbs#include <sys/linker.h> 3595378Sgibbs#include <sys/lock.h> 3695378Sgibbs#include <sys/malloc.h> 3795378Sgibbs#include <sys/mutex.h> 3895378Sgibbs#include <sys/proc.h> 3965942Sgibbs 40123579Sgibbs#include <geom/geom.h> 4165942Sgibbs 4265942Sgibbs#include <dev/ofw/openfirm.h> 4365942Sgibbs 4465942Sgibbs#define OFWD_BLOCKSIZE 512 4565942Sgibbs 4665942Sgibbsstruct ofwd_softc 4765942Sgibbs{ 4865942Sgibbs struct bio_queue_head ofwd_bio_queue; 4979874Sgibbs struct mtx ofwd_queue_mtx; 5074094Sgibbs ihandle_t ofwd_instance; 5174094Sgibbs off_t ofwd_mediasize; 5274094Sgibbs unsigned ofwd_sectorsize; 5365942Sgibbs unsigned ofwd_fwheads; 5465942Sgibbs unsigned ofwd_fwsectors; 5565942Sgibbs struct proc *ofwd_procp; 5665942Sgibbs struct g_geom *ofwd_gp; 5765942Sgibbs struct g_provider *ofwd_pp; 5865942Sgibbs} ofwd_softc; 5965942Sgibbs 6065942Sgibbsstatic g_init_t g_ofwd_init; 6165942Sgibbsstatic g_start_t g_ofwd_start; 6265942Sgibbsstatic g_access_t g_ofwd_access; 6365942Sgibbs 6465942Sgibbsstruct g_class g_ofwd_class = { 6565942Sgibbs .name = "OFWD", 6665942Sgibbs .version = G_VERSION, 6765942Sgibbs .init = g_ofwd_init, 6865942Sgibbs .start = g_ofwd_start, 6965942Sgibbs .access = g_ofwd_access, 7065942Sgibbs}; 7165942Sgibbs 7265942SgibbsDECLARE_GEOM_CLASS(g_ofwd_class, g_ofwd); 7365942Sgibbs 7474094Sgibbsstatic int ofwd_enable = 0; 7565942SgibbsTUNABLE_INT("kern.ofw.disk", &ofwd_enable); 7665942Sgibbs 7765942Sgibbsstatic int 7865942Sgibbsofwd_startio(struct ofwd_softc *sc, struct bio *bp) 7965942Sgibbs{ 8065942Sgibbs u_int r; 8165942Sgibbs 8265942Sgibbs r = OF_seek(sc->ofwd_instance, bp->bio_offset); 8365942Sgibbs 8465942Sgibbs switch (bp->bio_cmd) { 8565942Sgibbs case BIO_READ: 8665942Sgibbs r = OF_read(sc->ofwd_instance, (void *)bp->bio_data, 8774094Sgibbs bp->bio_length); 8865942Sgibbs break; 8965942Sgibbs case BIO_WRITE: 9065942Sgibbs r = OF_write(sc->ofwd_instance, (void *)bp->bio_data, 9165942Sgibbs bp->bio_length); 9265942Sgibbs break; 9365942Sgibbs } 9465942Sgibbs if (r != bp->bio_length) 9574094Sgibbs panic("ofwd: incorrect i/o count"); 9665942Sgibbs 9765942Sgibbs bp->bio_resid = 0; 9865942Sgibbs return (0); 9965942Sgibbs} 10065942Sgibbs 10165942Sgibbsstatic void 10265942Sgibbsofwd_kthread(void *arg) 10365942Sgibbs{ 10465942Sgibbs struct ofwd_softc *sc; 10565942Sgibbs struct bio *bp; 10665942Sgibbs int error; 10765942Sgibbs 10865942Sgibbs sc = arg; 10965942Sgibbs curthread->td_base_pri = PRIBIO; 11065942Sgibbs 11165942Sgibbs for (;;) { 11274094Sgibbs mtx_lock(&sc->ofwd_queue_mtx); 11365942Sgibbs bp = bioq_takefirst(&sc->ofwd_bio_queue); 11465942Sgibbs if (!bp) { 11565942Sgibbs msleep(sc, &sc->ofwd_queue_mtx, PRIBIO | PDROP, 11665942Sgibbs "ofwdwait", 0); 11765942Sgibbs continue; 11865942Sgibbs } 11965942Sgibbs mtx_unlock(&sc->ofwd_queue_mtx); 12065942Sgibbs if (bp->bio_cmd == BIO_GETATTR) { 12165942Sgibbs error = EOPNOTSUPP; 12265942Sgibbs } else 12365942Sgibbs error = ofwd_startio(sc, bp); 12465942Sgibbs 12565942Sgibbs if (error != -1) { 12665942Sgibbs bp->bio_completed = bp->bio_length; 12765942Sgibbs g_io_deliver(bp, error); 12865942Sgibbs } 12971390Sgibbs } 13065942Sgibbs} 13165942Sgibbs 13265942Sgibbsstatic void 13365942Sgibbsg_ofwd_init(struct g_class *mp __unused) 13465942Sgibbs{ 13565942Sgibbs char path[128]; 13665942Sgibbs char fname[32]; 13765942Sgibbs phandle_t ofd; 13865942Sgibbs struct ofwd_softc *sc; 13965942Sgibbs struct g_geom *gp; 14065942Sgibbs struct g_provider *pp; 14165942Sgibbs ihandle_t ifd; 14271390Sgibbs int error; 14365942Sgibbs 14465942Sgibbs if (ofwd_enable == 0) 14565942Sgibbs return; 14665942Sgibbs 14765942Sgibbs ofd = OF_finddevice("ofwdisk"); 14865942Sgibbs if (ofd == -1) 14965942Sgibbs return; 15065942Sgibbs 15165942Sgibbs bzero(path, 128); 15265942Sgibbs OF_package_to_path(ofd, path, 128); 15365942Sgibbs OF_getprop(ofd, "file", fname, sizeof(fname)); 15465942Sgibbs printf("ofw_disk located at %s, file %s\n", path, fname); 15565942Sgibbs ifd = OF_open(path); 15665942Sgibbs if (ifd == -1) { 15765942Sgibbs printf("ofw_disk: could not create instance\n"); 15879874Sgibbs return; 15979874Sgibbs } 16079874Sgibbs 16179874Sgibbs sc = (struct ofwd_softc *)malloc(sizeof *sc, M_DEVBUF, 16279874Sgibbs M_WAITOK | M_ZERO); 16379874Sgibbs bioq_init(&sc->ofwd_bio_queue); 16479874Sgibbs mtx_init(&sc->ofwd_queue_mtx, "ofwd bio queue", NULL, MTX_DEF); 16565942Sgibbs sc->ofwd_instance = ifd; 16665942Sgibbs sc->ofwd_mediasize = (off_t)2 * 33554432; 16765942Sgibbs sc->ofwd_sectorsize = OFWD_BLOCKSIZE; 16865942Sgibbs sc->ofwd_fwsectors = 0; 16965942Sgibbs sc->ofwd_fwheads = 0; 17065942Sgibbs error = kproc_create(ofwd_kthread, sc, &sc->ofwd_procp, 0, 0, 17165942Sgibbs "ofwd0"); 17265942Sgibbs if (error != 0) { 17365942Sgibbs free(sc, M_DEVBUF); 17465942Sgibbs return; 17565942Sgibbs } 17665942Sgibbs 17765942Sgibbs gp = g_new_geomf(&g_ofwd_class, "ofwd0"); 17865942Sgibbs gp->softc = sc; 17965942Sgibbs pp = g_new_providerf(gp, "ofwd0"); 18065942Sgibbs pp->mediasize = sc->ofwd_mediasize; 18165942Sgibbs pp->sectorsize = sc->ofwd_sectorsize; 18265942Sgibbs sc->ofwd_gp = gp; 18365942Sgibbs sc->ofwd_pp = pp; 18465942Sgibbs g_error_provider(pp, 0); 18565942Sgibbs} 18665942Sgibbs 18765942Sgibbsstatic void 18865942Sgibbsg_ofwd_start(struct bio *bp) 18965942Sgibbs{ 19065942Sgibbs struct ofwd_softc *sc; 19165942Sgibbs 19265942Sgibbs sc = bp->bio_to->geom->softc; 19365942Sgibbs mtx_lock(&sc->ofwd_queue_mtx); 19465942Sgibbs bioq_disksort(&sc->ofwd_bio_queue, bp); 19565942Sgibbs mtx_unlock(&sc->ofwd_queue_mtx); 19679874Sgibbs wakeup(sc); 19779874Sgibbs} 19879874Sgibbs 199123579Sgibbsstatic int 20079874Sgibbsg_ofwd_access(struct g_provider *pp, int r, int w, int e) 20179874Sgibbs{ 20279874Sgibbs 20379874Sgibbs if (pp->geom->softc == NULL) 20479874Sgibbs return (ENXIO); 20579874Sgibbs return (0); 20679874Sgibbs} 20779874Sgibbs