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