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