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