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