1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2008 Nathan Whitehorn. 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 ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bio.h>
31 #include <sys/bus.h>
32 #include <sys/conf.h>
33 #include <sys/kernel.h>
34 #include <sys/kthread.h>
35 #include <sys/lock.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/mutex.h>
39 #include <geom/geom_disk.h>
40
41 #include <powerpc/mambo/mambocall.h>
42
43 struct mambodisk_softc {
44 device_t dev;
45 struct mtx sc_mtx;
46 struct disk *disk;
47 struct proc *p;
48 struct bio_queue_head bio_queue;
49 int running;
50 int maxblocks;
51 };
52
53 #define MAMBO_DISK_READ 116
54 #define MAMBO_DISK_WRITE 117
55 #define MAMBO_DISK_INFO 118
56
57 #define MAMBO_INFO_STATUS 1
58 #define MAMBO_INFO_BLKSZ 2
59 #define MAMBO_INFO_DEVSZ 3
60
61 /* bus entry points */
62 static void mambodisk_identify(driver_t *driver, device_t parent);
63 static int mambodisk_probe(device_t dev);
64 static int mambodisk_attach(device_t dev);
65
66 /* disk routines */
67 static int mambodisk_open(struct disk *dp);
68 static int mambodisk_close(struct disk *dp);
69 static void mambodisk_strategy(struct bio *bp);
70 static void mambodisk_task(void *arg);
71
72 #define MBODISK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
73 #define MBODISK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
74 #define MBODISK_LOCK_INIT(_sc) \
75 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
76 "mambodisk", MTX_DEF)
77 #define MBODISK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
78 #define MBODISK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
79 #define MBODISK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
80
81 static void
mambodisk_identify(driver_t * driver,device_t parent)82 mambodisk_identify(driver_t *driver, device_t parent)
83 {
84 int i = 0;
85
86 for (i = 0; mambocall(MAMBO_DISK_INFO,MAMBO_INFO_DEVSZ,i) > 0; i++)
87 BUS_ADD_CHILD(parent,0,"mambodisk",i);
88 }
89
90 static int
mambodisk_probe(device_t dev)91 mambodisk_probe(device_t dev)
92 {
93 device_set_desc(dev, "Mambo Simulated Block Device");
94 return (0);
95 }
96
97 static int
mambodisk_attach(device_t dev)98 mambodisk_attach(device_t dev)
99 {
100 struct mambodisk_softc *sc;
101 struct disk *d;
102 intmax_t mb;
103 char unit;
104
105 sc = device_get_softc(dev);
106 sc->dev = dev;
107 MBODISK_LOCK_INIT(sc);
108
109 d = sc->disk = disk_alloc();
110 d->d_open = mambodisk_open;
111 d->d_close = mambodisk_close;
112 d->d_strategy = mambodisk_strategy;
113 d->d_name = "mambodisk";
114 d->d_drv1 = sc;
115 d->d_maxsize = maxphys; /* Maybe ask bridge? */
116
117 d->d_sectorsize = 512;
118 sc->maxblocks = mambocall(MAMBO_DISK_INFO,MAMBO_INFO_BLKSZ,d->d_unit)
119 / 512;
120
121 d->d_unit = device_get_unit(dev);
122 d->d_mediasize = mambocall(MAMBO_DISK_INFO,MAMBO_INFO_DEVSZ,d->d_unit)
123 * 1024ULL; /* Mambo gives size in KB */
124
125 mb = d->d_mediasize >> 20; /* 1MiB == 1 << 20 */
126 unit = 'M';
127 if (mb >= 10240) { /* 1GiB = 1024 MiB */
128 unit = 'G';
129 mb /= 1024;
130 }
131 device_printf(dev, "%ju%cB, %d byte sectors\n", mb, unit,
132 d->d_sectorsize);
133 disk_create(d, DISK_VERSION);
134 bioq_init(&sc->bio_queue);
135
136 sc->running = 1;
137 kproc_create(&mambodisk_task, sc, &sc->p, 0, 0, "task: mambo hd");
138
139 return (0);
140 }
141
142 static int
mambodisk_detach(device_t dev)143 mambodisk_detach(device_t dev)
144 {
145 struct mambodisk_softc *sc = device_get_softc(dev);
146
147 /* kill thread */
148 MBODISK_LOCK(sc);
149 sc->running = 0;
150 wakeup(sc);
151 MBODISK_UNLOCK(sc);
152
153 /* wait for thread to finish. XXX probably want timeout. -sorbo */
154 MBODISK_LOCK(sc);
155 while (sc->running != -1)
156 msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0);
157 MBODISK_UNLOCK(sc);
158
159 /* kill disk */
160 disk_destroy(sc->disk);
161 /* XXX destroy anything in queue */
162
163 MBODISK_LOCK_DESTROY(sc);
164
165 return (0);
166 }
167
168 static int
mambodisk_open(struct disk * dp)169 mambodisk_open(struct disk *dp)
170 {
171 return (0);
172 }
173
174 static int
mambodisk_close(struct disk * dp)175 mambodisk_close(struct disk *dp)
176 {
177 return (0);
178 }
179
180 static void
mambodisk_strategy(struct bio * bp)181 mambodisk_strategy(struct bio *bp)
182 {
183 struct mambodisk_softc *sc;
184
185 sc = (struct mambodisk_softc *)bp->bio_disk->d_drv1;
186 MBODISK_LOCK(sc);
187 bioq_disksort(&sc->bio_queue, bp);
188 wakeup(sc);
189 MBODISK_UNLOCK(sc);
190 }
191
192 static void
mambodisk_task(void * arg)193 mambodisk_task(void *arg)
194 {
195 struct mambodisk_softc *sc = (struct mambodisk_softc*)arg;
196 struct bio *bp;
197 size_t sz;
198 int result;
199 daddr_t block, end;
200 device_t dev;
201 u_long unit;
202
203 dev = sc->dev;
204 unit = device_get_unit(dev);
205
206 while (sc->running) {
207 MBODISK_LOCK(sc);
208 do {
209 bp = bioq_first(&sc->bio_queue);
210 if (bp == NULL)
211 msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);
212 } while (bp == NULL && sc->running);
213 if (bp)
214 bioq_remove(&sc->bio_queue, bp);
215 MBODISK_UNLOCK(sc);
216 if (!sc->running)
217 break;
218 sz = sc->disk->d_sectorsize;
219 end = bp->bio_pblkno + (bp->bio_bcount / sz);
220 for (block = bp->bio_pblkno; block < end;) {
221 u_long numblocks;
222 char *vaddr = bp->bio_data +
223 (block - bp->bio_pblkno) * sz;
224
225 numblocks = end - block;
226 if (numblocks > sc->maxblocks)
227 numblocks = sc->maxblocks;
228
229 if (bp->bio_cmd == BIO_READ) {
230 result = mambocall(MAMBO_DISK_READ, vaddr,
231 (u_long)block, (numblocks << 16) | unit);
232 } else if (bp->bio_cmd == BIO_WRITE) {
233 result = mambocall(MAMBO_DISK_WRITE, vaddr,
234 (u_long)block, (numblocks << 16) | unit);
235 } else {
236 result = 1;
237 }
238
239 if (result)
240 break;
241
242 block += numblocks;
243 }
244 if (block < end) {
245 bp->bio_error = EIO;
246 bp->bio_resid = (end - block) * sz;
247 bp->bio_flags |= BIO_ERROR;
248 }
249 biodone(bp);
250 }
251
252 /* tell parent we're done */
253 MBODISK_LOCK(sc);
254 sc->running = -1;
255 wakeup(sc);
256 MBODISK_UNLOCK(sc);
257
258 kproc_exit(0);
259 }
260
261 static device_method_t mambodisk_methods[] = {
262 DEVMETHOD(device_identify, mambodisk_identify),
263 DEVMETHOD(device_probe, mambodisk_probe),
264 DEVMETHOD(device_attach, mambodisk_attach),
265 DEVMETHOD(device_detach, mambodisk_detach),
266 {0, 0},
267 };
268
269 static driver_t mambodisk_driver = {
270 "mambodisk",
271 mambodisk_methods,
272 sizeof(struct mambodisk_softc),
273 };
274
275 DRIVER_MODULE(mambodisk, mambo, mambodisk_driver, 0, 0);
276