xref: /freebsd/sys/dev/ofw/ofw_disk.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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