]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/sun4v/sun4v/simdisk.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / sun4v / sun4v / simdisk.c
1 /*-
2  * Copyright (c) 2006 Kip Macy
3  * Copyright (c) 2001 Benno Rice
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
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 <vm/vm.h>
43 #include <vm/pmap.h>
44
45 #include <geom/geom.h>
46
47 #include <dev/ofw/ofw_bus.h>
48 #include <dev/ofw/ofw_bus_subr.h>
49 #include <dev/ofw/openfirm.h>
50
51
52 #include <machine/hv_api.h>
53
54 #define HVD_BLOCKSIZE   512
55
56 struct hvd_softc
57 {
58         struct bio_queue_head hvd_bio_queue;
59         struct mtx      hvd_queue_mtx;
60         off_t           hvd_mediasize;
61         unsigned        hvd_sectorsize;
62         unsigned        hvd_fwheads;
63         unsigned        hvd_fwsectors;
64         struct proc     *hvd_procp;
65         struct g_geom   *hvd_gp;
66         struct g_provider *hvd_pp;
67 } hvd_softc;
68
69 static g_init_t g_hvd_init;
70 static g_start_t g_hvd_start;
71 static g_access_t g_hvd_access;
72
73 struct g_class g_hvd_class = {
74         .name = "HVD",
75         .version = G_VERSION,
76         .init = g_hvd_init,
77         .start = g_hvd_start,
78         .access = g_hvd_access,
79 };
80
81 DECLARE_GEOM_CLASS(g_hvd_class, g_hvd);
82
83
84
85 static int
86 hvd_startio(struct hvd_softc *sc, struct bio *bp)
87 {
88         u_int r;
89         int len, rlen, wlen;
90         uint64_t page_off;
91
92         r = H_EOK;
93         len = 0;
94
95         page_off = bp->bio_offset & PAGE_MASK;
96
97
98         switch (bp->bio_cmd) {
99         case BIO_READ:
100                 if (bp->bio_length > (PAGE_SIZE - page_off)) {
101                         len = rlen = (PAGE_SIZE - page_off);
102                         r = hv_sim_read(bp->bio_offset, vtophys((char *)bp->bio_data), rlen);
103                 }
104                 for (; len < bp->bio_length && r == H_EOK; len += PAGE_SIZE) {
105                         rlen = (bp->bio_length - len) > PAGE_SIZE ? PAGE_SIZE : bp->bio_length - len;
106                         r = hv_sim_read(bp->bio_offset + len, vtophys((char *)bp->bio_data + len), rlen);
107
108                 }
109                 break;
110         case BIO_WRITE:
111                 if (bp->bio_length > (PAGE_SIZE - page_off)) {
112                         len = wlen = (PAGE_SIZE - page_off);
113                         r = hv_sim_write(bp->bio_offset, vtophys((char *)bp->bio_data), wlen);
114                 }
115                 for (; len < bp->bio_length && r == H_EOK; len += PAGE_SIZE) {
116                         wlen = (bp->bio_length - len) > PAGE_SIZE ? PAGE_SIZE : bp->bio_length - len;
117                         r = hv_sim_write(bp->bio_offset + len, vtophys((char *)bp->bio_data + len), wlen);
118                 }
119                 break;
120         }
121         if (r != H_EOK)
122                 panic("invalid I/O");
123
124         bp->bio_resid = 0;
125         return (0);
126 }
127
128 static void
129 hvd_kthread(void *arg)
130 {
131         struct hvd_softc *sc;
132         struct bio *bp;
133         int error;
134
135         sc = arg;
136         curthread->td_base_pri = PRIBIO;
137
138         for (;;) {
139                 mtx_lock(&sc->hvd_queue_mtx);
140                 bp = bioq_takefirst(&sc->hvd_bio_queue);
141                 if (!bp) {
142                         msleep(sc, &sc->hvd_queue_mtx, PRIBIO | PDROP,
143                             "hvdwait", 0);
144                         continue;
145                 }
146                 mtx_unlock(&sc->hvd_queue_mtx);
147                 if (bp->bio_cmd == BIO_GETATTR) {
148                         error = EOPNOTSUPP;
149                 } else
150                         error = hvd_startio(sc, bp);
151
152                 if (error != -1) {
153                         bp->bio_completed = bp->bio_length;
154                         g_io_deliver(bp, error);
155                 }
156         }
157 }
158
159 static void
160 g_hvd_init(struct g_class *mp __unused)
161 {
162         struct hvd_softc *sc;
163         struct g_geom *gp;
164         struct g_provider *pp;
165         int     error;
166         printf("calling g_hvd_init\n");
167
168         sc = (struct hvd_softc *)malloc(sizeof *sc, M_DEVBUF,
169                  M_WAITOK|M_ZERO);
170         bioq_init(&sc->hvd_bio_queue);
171         mtx_init(&sc->hvd_queue_mtx, "hvd bio queue", NULL, MTX_DEF);
172         sc->hvd_mediasize = (off_t)0x20000000;
173         sc->hvd_sectorsize = HVD_BLOCKSIZE;
174         sc->hvd_fwsectors = 0;
175         sc->hvd_fwheads = 0;
176         error = kproc_create(hvd_kthread, sc, &sc->hvd_procp, 0, 0,
177                      "hvd0");
178         if (error != 0) {
179                 free(sc, M_DEVBUF);
180                 return;
181         }
182
183         gp = g_new_geomf(&g_hvd_class, "hvd0");
184         gp->softc = sc;
185         pp = g_new_providerf(gp, "hvd0");
186         pp->mediasize = sc->hvd_mediasize;
187         pp->sectorsize = sc->hvd_sectorsize;
188         sc->hvd_gp = gp;
189         sc->hvd_pp = pp;
190         g_error_provider(pp, 0);
191 }
192
193 static void
194 g_hvd_start(struct bio *bp)
195 {
196         struct hvd_softc *sc;
197 #if 0
198         printf("in hvd_start\n");
199 #endif
200         sc = bp->bio_to->geom->softc;
201         mtx_lock(&sc->hvd_queue_mtx);
202         bioq_disksort(&sc->hvd_bio_queue, bp);
203         mtx_unlock(&sc->hvd_queue_mtx);
204         wakeup(sc);
205 }
206
207 static int
208 g_hvd_access(struct g_provider *pp, int r, int w, int e)
209 {
210
211         if (pp->geom->softc == NULL)
212                 return (ENXIO);
213         return (0);
214 }
215
216 static int
217 hvd_probe(device_t dev)
218 {
219
220         if (strcmp(ofw_bus_get_name(dev), "disk"))
221                 return (ENXIO);
222         
223         device_set_desc(dev, "sun4v virtual disk");     
224
225         return (0);
226 }
227
228
229 static int
230 hvd_attach(device_t dev)
231 {
232         return (0);
233 }
234
235 static device_method_t hvd_methods[] = {
236         DEVMETHOD(device_probe, hvd_probe),
237         DEVMETHOD(device_attach, hvd_attach),
238         {0, 0}
239 };
240
241
242 static driver_t hvd_driver = {
243         "hvd",
244         hvd_methods,
245         0,
246 };
247
248
249 static devclass_t hvd_devclass;
250
251 DRIVER_MODULE(hvd, vnex, hvd_driver, hvd_devclass, 0, 0);