ofw_disk.c revision 172836
1169695Skan/*-
2169695Skan * Copyright (C) 2002 Benno Rice <benno@FreeBSD.org>
3169695Skan * All rights reserved.
4169695Skan *
5169695Skan * Redistribution and use in source and binary forms, with or without
6169695Skan * modification, are permitted provided that the following conditions
7169695Skan * are met:
8169695Skan * 1. Redistributions of source code must retain the above copyright
9169695Skan *    notice, this list of conditions and the following disclaimer.
10169695Skan * 2. Redistributions in binary form must reproduce the above copyright
11169695Skan *    notice, this list of conditions and the following disclaimer in the
12169695Skan *    documentation and/or other materials provided with the distribution.
13169695Skan *
14169695Skan * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15169695Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16169695Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17169695Skan * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18169695Skan * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19169695Skan * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20169695Skan * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21169695Skan * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22169695Skan * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23169695Skan * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24169695Skan *
25169695Skan *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/dev/ofw/ofw_disk.c 172836 2007-10-20 23:23:23Z julian $");
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 ofwd_enable = 0;
77TUNABLE_INT("kern.ofw.disk", &ofwd_enable);
78
79static int
80ofwd_startio(struct ofwd_softc *sc, struct bio *bp)
81{
82	u_int r;
83
84	r = OF_seek(sc->ofwd_instance, bp->bio_offset);
85
86        switch (bp->bio_cmd) {
87        case BIO_READ:
88		r = OF_read(sc->ofwd_instance, (void *)bp->bio_data,
89		        bp->bio_length);
90                break;
91        case BIO_WRITE:
92		r = OF_write(sc->ofwd_instance, (void *)bp->bio_data,
93		        bp->bio_length);
94                break;
95        }
96	if (r != bp->bio_length)
97		panic("ofwd: incorrect i/o count");
98
99        bp->bio_resid = 0;
100        return (0);
101}
102
103static void
104ofwd_kthread(void *arg)
105{
106	struct ofwd_softc *sc;
107	struct bio *bp;
108	int error;
109
110        sc = arg;
111        curthread->td_base_pri = PRIBIO;
112
113        for (;;) {
114		mtx_lock(&sc->ofwd_queue_mtx);
115		bp = bioq_takefirst(&sc->ofwd_bio_queue);
116		if (!bp) {
117			msleep(sc, &sc->ofwd_queue_mtx, PRIBIO | PDROP,
118			    "ofwdwait", 0);
119                        continue;
120		}
121                mtx_unlock(&sc->ofwd_queue_mtx);
122                if (bp->bio_cmd == BIO_GETATTR) {
123			error = EOPNOTSUPP;
124                } else
125			error = ofwd_startio(sc, bp);
126
127		if (error != -1) {
128                        bp->bio_completed = bp->bio_length;
129                        g_io_deliver(bp, error);
130                }
131	}
132}
133
134static void
135g_ofwd_init(struct g_class *mp __unused)
136{
137	struct ofwd_softc *sc;
138        struct g_geom *gp;
139        struct g_provider *pp;
140	char	path[128];
141	char	fname[32];
142	phandle_t ofd;
143	ihandle_t ifd;
144	int	error;
145
146	if (ofwd_enable == 0)
147		return;
148
149	ofd = OF_finddevice("ofwdisk");
150	if (ofd == -1)
151		return;
152
153	bzero(path, 128);
154	OF_package_to_path(ofd, path, 128);
155	OF_getprop(ofd, "file", fname, sizeof(fname));
156	printf("ofw_disk located at %s, file %s\n", path, fname);
157	ifd = OF_open(path);
158	if (ifd == -1) {
159		printf("ofw_disk: could not create instance\n");
160		return;
161	}
162
163	sc = (struct ofwd_softc *)malloc(sizeof *sc, M_DEVBUF,
164	         M_WAITOK|M_ZERO);
165	bioq_init(&sc->ofwd_bio_queue);
166        mtx_init(&sc->ofwd_queue_mtx, "ofwd bio queue", NULL, MTX_DEF);
167	sc->ofwd_instance = ifd;
168	sc->ofwd_mediasize = (off_t)2*33554432;
169	sc->ofwd_sectorsize = OFWD_BLOCKSIZE;
170	sc->ofwd_fwsectors = 0;
171	sc->ofwd_fwheads = 0;
172	error = kproc_create(ofwd_kthread, sc, &sc->ofwd_procp, 0, 0,
173		     "ofwd0");
174        if (error != 0) {
175		free(sc, M_DEVBUF);
176                return;
177	}
178
179	gp = g_new_geomf(&g_ofwd_class, "ofwd0");
180	gp->softc = sc;
181	pp = g_new_providerf(gp, "ofwd0");
182	pp->mediasize = sc->ofwd_mediasize;
183	pp->sectorsize = sc->ofwd_sectorsize;
184	sc->ofwd_gp = gp;
185	sc->ofwd_pp = pp;
186	g_error_provider(pp, 0);
187}
188
189static void
190g_ofwd_start(struct bio *bp)
191{
192        struct ofwd_softc *sc;
193
194        sc = bp->bio_to->geom->softc;
195        mtx_lock(&sc->ofwd_queue_mtx);
196        bioq_disksort(&sc->ofwd_bio_queue, bp);
197        mtx_unlock(&sc->ofwd_queue_mtx);
198        wakeup(sc);
199}
200
201static int
202g_ofwd_access(struct g_provider *pp, int r, int w, int e)
203{
204
205	if (pp->geom->softc == NULL)
206		return (ENXIO);
207        return (0);
208}
209