1 /*- 2 * Copyright (c) 2008 Nathan Whitehorn. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (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$"); 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 44 struct 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 */ 63 static void mambodisk_identify(driver_t *driver, device_t parent); 64 static int mambodisk_probe(device_t dev); 65 static int mambodisk_attach(device_t dev); 66 67 /* disk routines */ 68 static int mambodisk_open(struct disk *dp); 69 static int mambodisk_close(struct disk *dp); 70 static void mambodisk_strategy(struct bio *bp); 71 static 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 82 static void 83 mambodisk_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 91 static int 92 mambodisk_probe(device_t dev) 93 { 94 device_set_desc(dev, "Mambo Simulated Block Device"); 95 return (0); 96 } 97 98 static int 99 mambodisk_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 143 static int 144 mambodisk_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 169 static int 170 mambodisk_open(struct disk *dp) 171 { 172 return (0); 173 } 174 175 static int 176 mambodisk_close(struct disk *dp) 177 { 178 return (0); 179 } 180 181 static void 182 mambodisk_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 193 static void 194 mambodisk_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 262 static 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 270 static driver_t mambodisk_driver = { 271 "mambodisk", 272 mambodisk_methods, 273 sizeof(struct mambodisk_softc), 274 }; 275 static devclass_t mambodisk_devclass; 276 277 DRIVER_MODULE(mambodisk, mambo, mambodisk_driver, mambodisk_devclass, 0, 0); 278