xref: /freebsd/sys/powerpc/mambo/mambo_disk.c (revision 3494f7c0)
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
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
91 mambodisk_probe(device_t dev)
92 {
93 	device_set_desc(dev, "Mambo Simulated Block Device");
94 	return (0);
95 }
96 
97 static int
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
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
169 mambodisk_open(struct disk *dp)
170 {
171 	return (0);
172 }
173 
174 static int
175 mambodisk_close(struct disk *dp)
176 {
177 	return (0);
178 }
179 
180 static void
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
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