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