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