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