1210677Snwhitehorn/*-
2210677Snwhitehorn * Copyright (c) 2008 Nathan Whitehorn.  All rights reserved.
3210677Snwhitehorn *
4210677Snwhitehorn * Redistribution and use in source and binary forms, with or without
5210677Snwhitehorn * modification, are permitted provided that the following conditions
6210677Snwhitehorn * are met:
7210677Snwhitehorn * 1. Redistributions of source code must retain the above copyright
8210677Snwhitehorn *    notice, this list of conditions and the following disclaimer.
9210677Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
10210677Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
11210677Snwhitehorn *    documentation and/or other materials provided with the distribution.
12210677Snwhitehorn *
13210677Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14210677Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15210677Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16210677Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17210677Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18210677Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19210677Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20210677Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21210677Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22210677Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23210677Snwhitehorn *
24210677Snwhitehorn */
25210677Snwhitehorn
26210677Snwhitehorn#include <sys/cdefs.h>
27210677Snwhitehorn__FBSDID("$FreeBSD$");
28210677Snwhitehorn
29210677Snwhitehorn#include <sys/param.h>
30210677Snwhitehorn#include <sys/systm.h>
31210677Snwhitehorn#include <sys/bio.h>
32210677Snwhitehorn#include <sys/bus.h>
33210677Snwhitehorn#include <sys/conf.h>
34210677Snwhitehorn#include <sys/kernel.h>
35210677Snwhitehorn#include <sys/kthread.h>
36210677Snwhitehorn#include <sys/lock.h>
37210677Snwhitehorn#include <sys/malloc.h>
38210677Snwhitehorn#include <sys/module.h>
39210677Snwhitehorn#include <sys/mutex.h>
40210677Snwhitehorn#include <geom/geom_disk.h>
41210677Snwhitehorn
42210677Snwhitehorn#include <powerpc/mambo/mambocall.h>
43210677Snwhitehorn
44210677Snwhitehornstruct mambodisk_softc {
45210677Snwhitehorn	device_t dev;
46210677Snwhitehorn	struct mtx sc_mtx;
47210677Snwhitehorn	struct disk *disk;
48210677Snwhitehorn	struct proc *p;
49210677Snwhitehorn	struct bio_queue_head bio_queue;
50210677Snwhitehorn	int running;
51210677Snwhitehorn	int maxblocks;
52210677Snwhitehorn};
53210677Snwhitehorn
54210677Snwhitehorn#define MAMBO_DISK_READ		116
55210677Snwhitehorn#define	MAMBO_DISK_WRITE	117
56210677Snwhitehorn#define MAMBO_DISK_INFO		118
57210677Snwhitehorn
58210677Snwhitehorn#define MAMBO_INFO_STATUS	1
59210677Snwhitehorn#define MAMBO_INFO_BLKSZ	2
60210677Snwhitehorn#define MAMBO_INFO_DEVSZ	3
61210677Snwhitehorn
62210677Snwhitehorn/* bus entry points */
63210677Snwhitehornstatic void mambodisk_identify(driver_t *driver, device_t parent);
64210677Snwhitehornstatic int mambodisk_probe(device_t dev);
65210677Snwhitehornstatic int mambodisk_attach(device_t dev);
66210677Snwhitehorn
67210677Snwhitehorn/* disk routines */
68210677Snwhitehornstatic int mambodisk_open(struct disk *dp);
69210677Snwhitehornstatic int mambodisk_close(struct disk *dp);
70210677Snwhitehornstatic void mambodisk_strategy(struct bio *bp);
71210677Snwhitehornstatic void mambodisk_task(void *arg);
72210677Snwhitehorn
73210677Snwhitehorn#define MBODISK_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
74210677Snwhitehorn#define	MBODISK_UNLOCK(_sc)	mtx_unlock(&(_sc)->sc_mtx)
75210677Snwhitehorn#define MBODISK_LOCK_INIT(_sc) \
76210677Snwhitehorn	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
77210677Snwhitehorn	    "mambodisk", MTX_DEF)
78210677Snwhitehorn#define MBODISK_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
79210677Snwhitehorn#define MBODISK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
80210677Snwhitehorn#define MBODISK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
81210677Snwhitehorn
82210677Snwhitehornstatic void
83210677Snwhitehornmambodisk_identify(driver_t *driver, device_t parent)
84210677Snwhitehorn{
85210677Snwhitehorn	int i = 0;
86210677Snwhitehorn
87210677Snwhitehorn	for (i = 0; mambocall(MAMBO_DISK_INFO,MAMBO_INFO_DEVSZ,i) > 0; i++)
88210677Snwhitehorn		BUS_ADD_CHILD(parent,0,"mambodisk",i);
89210677Snwhitehorn}
90210677Snwhitehorn
91210677Snwhitehornstatic int
92210677Snwhitehornmambodisk_probe(device_t dev)
93210677Snwhitehorn{
94210677Snwhitehorn	device_set_desc(dev, "Mambo Simulated Block Device");
95210677Snwhitehorn	return (0);
96210677Snwhitehorn}
97210677Snwhitehorn
98210677Snwhitehornstatic int
99210677Snwhitehornmambodisk_attach(device_t dev)
100210677Snwhitehorn{
101210677Snwhitehorn	struct mambodisk_softc *sc;
102210677Snwhitehorn	struct disk *d;
103210677Snwhitehorn	intmax_t mb;
104210677Snwhitehorn	char unit;
105210677Snwhitehorn
106210677Snwhitehorn	sc = device_get_softc(dev);
107210677Snwhitehorn	sc->dev = dev;
108210677Snwhitehorn	MBODISK_LOCK_INIT(sc);
109210677Snwhitehorn
110210677Snwhitehorn	d = sc->disk = disk_alloc();
111210677Snwhitehorn	d->d_open = mambodisk_open;
112210677Snwhitehorn	d->d_close = mambodisk_close;
113210677Snwhitehorn	d->d_strategy = mambodisk_strategy;
114210677Snwhitehorn	d->d_name = "mambodisk";
115210677Snwhitehorn	d->d_drv1 = sc;
116210677Snwhitehorn	d->d_maxsize = MAXPHYS;		/* Maybe ask bridge? */
117210677Snwhitehorn
118210677Snwhitehorn	d->d_sectorsize = 512;
119210677Snwhitehorn	sc->maxblocks = mambocall(MAMBO_DISK_INFO,MAMBO_INFO_BLKSZ,d->d_unit)
120210677Snwhitehorn	    / 512;
121210677Snwhitehorn
122210677Snwhitehorn	d->d_unit = device_get_unit(dev);
123210677Snwhitehorn	d->d_mediasize = mambocall(MAMBO_DISK_INFO,MAMBO_INFO_DEVSZ,d->d_unit)
124210677Snwhitehorn	    * 1024ULL; /* Mambo gives size in KB */
125210677Snwhitehorn
126210677Snwhitehorn	mb = d->d_mediasize >> 20;	/* 1MiB == 1 << 20 */
127210677Snwhitehorn	unit = 'M';
128210677Snwhitehorn	if (mb >= 10240) {		/* 1GiB = 1024 MiB */
129210677Snwhitehorn		unit = 'G';
130210677Snwhitehorn		mb /= 1024;
131210677Snwhitehorn	}
132210677Snwhitehorn	device_printf(dev, "%ju%cB, %d byte sectors\n", mb, unit,
133210677Snwhitehorn	    d->d_sectorsize);
134210677Snwhitehorn	disk_create(d, DISK_VERSION);
135210677Snwhitehorn	bioq_init(&sc->bio_queue);
136210677Snwhitehorn
137210677Snwhitehorn	sc->running = 1;
138210677Snwhitehorn	kproc_create(&mambodisk_task, sc, &sc->p, 0, 0, "task: mambo hd");
139210677Snwhitehorn
140210677Snwhitehorn	return (0);
141210677Snwhitehorn}
142210677Snwhitehorn
143210677Snwhitehornstatic int
144210677Snwhitehornmambodisk_detach(device_t dev)
145210677Snwhitehorn{
146210677Snwhitehorn	struct mambodisk_softc *sc = device_get_softc(dev);
147210677Snwhitehorn
148210677Snwhitehorn	/* kill thread */
149210677Snwhitehorn	MBODISK_LOCK(sc);
150210677Snwhitehorn	sc->running = 0;
151210677Snwhitehorn	wakeup(sc);
152210677Snwhitehorn	MBODISK_UNLOCK(sc);
153210677Snwhitehorn
154210677Snwhitehorn	/* wait for thread to finish.  XXX probably want timeout.  -sorbo */
155210677Snwhitehorn	MBODISK_LOCK(sc);
156210677Snwhitehorn	while (sc->running != -1)
157210677Snwhitehorn		msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0);
158210677Snwhitehorn	MBODISK_UNLOCK(sc);
159210677Snwhitehorn
160210677Snwhitehorn	/* kill disk */
161210677Snwhitehorn	disk_destroy(sc->disk);
162210677Snwhitehorn	/* XXX destroy anything in queue */
163210677Snwhitehorn
164210677Snwhitehorn	MBODISK_LOCK_DESTROY(sc);
165210677Snwhitehorn
166210677Snwhitehorn	return (0);
167210677Snwhitehorn}
168210677Snwhitehorn
169210677Snwhitehornstatic int
170210677Snwhitehornmambodisk_open(struct disk *dp)
171210677Snwhitehorn{
172210677Snwhitehorn	return (0);
173210677Snwhitehorn}
174210677Snwhitehorn
175210677Snwhitehornstatic int
176210677Snwhitehornmambodisk_close(struct disk *dp)
177210677Snwhitehorn{
178210677Snwhitehorn	return (0);
179210677Snwhitehorn}
180210677Snwhitehorn
181210677Snwhitehornstatic void
182210677Snwhitehornmambodisk_strategy(struct bio *bp)
183210677Snwhitehorn{
184210677Snwhitehorn	struct mambodisk_softc *sc;
185210677Snwhitehorn
186210677Snwhitehorn	sc = (struct mambodisk_softc *)bp->bio_disk->d_drv1;
187210677Snwhitehorn	MBODISK_LOCK(sc);
188210677Snwhitehorn	bioq_disksort(&sc->bio_queue, bp);
189210677Snwhitehorn	wakeup(sc);
190210677Snwhitehorn	MBODISK_UNLOCK(sc);
191210677Snwhitehorn}
192210677Snwhitehorn
193210677Snwhitehornstatic void
194210677Snwhitehornmambodisk_task(void *arg)
195210677Snwhitehorn{
196210677Snwhitehorn	struct mambodisk_softc *sc = (struct mambodisk_softc*)arg;
197210677Snwhitehorn	struct bio *bp;
198210677Snwhitehorn	size_t sz;
199210677Snwhitehorn	int result;
200210677Snwhitehorn	daddr_t block, end;
201210677Snwhitehorn	device_t dev;
202210677Snwhitehorn	u_long unit;
203210677Snwhitehorn
204210677Snwhitehorn	dev = sc->dev;
205210677Snwhitehorn	unit = device_get_unit(dev);
206210677Snwhitehorn
207210677Snwhitehorn	while (sc->running) {
208210677Snwhitehorn		MBODISK_LOCK(sc);
209210677Snwhitehorn		do {
210210677Snwhitehorn			bp = bioq_first(&sc->bio_queue);
211210677Snwhitehorn			if (bp == NULL)
212210677Snwhitehorn				msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);
213210677Snwhitehorn		} while (bp == NULL && sc->running);
214210677Snwhitehorn		if (bp)
215210677Snwhitehorn			bioq_remove(&sc->bio_queue, bp);
216210677Snwhitehorn		MBODISK_UNLOCK(sc);
217210677Snwhitehorn		if (!sc->running)
218210677Snwhitehorn			break;
219210677Snwhitehorn		sz = sc->disk->d_sectorsize;
220210677Snwhitehorn		end = bp->bio_pblkno + (bp->bio_bcount / sz);
221210677Snwhitehorn		for (block = bp->bio_pblkno; block < end;) {
222210677Snwhitehorn			u_long numblocks;
223210677Snwhitehorn			char *vaddr = bp->bio_data +
224210677Snwhitehorn			    (block - bp->bio_pblkno) * sz;
225210677Snwhitehorn
226210677Snwhitehorn			numblocks = end - block;
227210677Snwhitehorn			if (numblocks > sc->maxblocks)
228210677Snwhitehorn				numblocks = sc->maxblocks;
229210677Snwhitehorn
230210677Snwhitehorn			if (bp->bio_cmd == BIO_READ) {
231210677Snwhitehorn				result = mambocall(MAMBO_DISK_READ, vaddr,
232210677Snwhitehorn				  (u_long)block, (numblocks << 16) | unit);
233210677Snwhitehorn			} else if (bp->bio_cmd == BIO_WRITE) {
234210677Snwhitehorn				result = mambocall(MAMBO_DISK_WRITE, vaddr,
235210677Snwhitehorn				  (u_long)block, (numblocks << 16) | unit);
236210677Snwhitehorn			} else {
237210677Snwhitehorn				result = 1;
238210677Snwhitehorn			}
239210677Snwhitehorn
240210677Snwhitehorn			if (result)
241210677Snwhitehorn				break;
242210677Snwhitehorn
243210677Snwhitehorn			block += numblocks;
244210677Snwhitehorn		}
245210677Snwhitehorn		if (block < end) {
246210677Snwhitehorn			bp->bio_error = EIO;
247210677Snwhitehorn			bp->bio_resid = (end - block) * sz;
248210677Snwhitehorn			bp->bio_flags |= BIO_ERROR;
249210677Snwhitehorn		}
250210677Snwhitehorn		biodone(bp);
251210677Snwhitehorn	}
252210677Snwhitehorn
253210677Snwhitehorn	/* tell parent we're done */
254210677Snwhitehorn	MBODISK_LOCK(sc);
255210677Snwhitehorn	sc->running = -1;
256210677Snwhitehorn	wakeup(sc);
257210677Snwhitehorn	MBODISK_UNLOCK(sc);
258210677Snwhitehorn
259210677Snwhitehorn	kproc_exit(0);
260210677Snwhitehorn}
261210677Snwhitehorn
262210677Snwhitehornstatic device_method_t mambodisk_methods[] = {
263210677Snwhitehorn	DEVMETHOD(device_identify,	mambodisk_identify),
264210677Snwhitehorn	DEVMETHOD(device_probe,		mambodisk_probe),
265210677Snwhitehorn	DEVMETHOD(device_attach,	mambodisk_attach),
266210677Snwhitehorn	DEVMETHOD(device_detach,	mambodisk_detach),
267210677Snwhitehorn	{0, 0},
268210677Snwhitehorn};
269210677Snwhitehorn
270210677Snwhitehornstatic driver_t mambodisk_driver = {
271210677Snwhitehorn	"mambodisk",
272210677Snwhitehorn	mambodisk_methods,
273210677Snwhitehorn	sizeof(struct mambodisk_softc),
274210677Snwhitehorn};
275210677Snwhitehornstatic devclass_t mambodisk_devclass;
276210677Snwhitehorn
277210677SnwhitehornDRIVER_MODULE(mambodisk, mambo, mambodisk_driver, mambodisk_devclass, 0, 0);
278