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