1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/bio.h> 34 #include <sys/bus.h> 35 #include <sys/conf.h> 36 #include <sys/kernel.h> 37 #include <sys/kthread.h> 38 #include <sys/lock.h> 39 #include <sys/malloc.h> 40 #include <sys/module.h> 41 #include <sys/mutex.h> 42 #include <geom/geom_disk.h> 43 44 #include <powerpc/mambo/mambocall.h> 45 46 struct mambodisk_softc { 47 device_t dev; 48 struct mtx sc_mtx; 49 struct disk *disk; 50 struct proc *p; 51 struct bio_queue_head bio_queue; 52 int running; 53 int maxblocks; 54 }; 55 56 #define MAMBO_DISK_READ 116 57 #define MAMBO_DISK_WRITE 117 58 #define MAMBO_DISK_INFO 118 59 60 #define MAMBO_INFO_STATUS 1 61 #define MAMBO_INFO_BLKSZ 2 62 #define MAMBO_INFO_DEVSZ 3 63 64 /* bus entry points */ 65 static void mambodisk_identify(driver_t *driver, device_t parent); 66 static int mambodisk_probe(device_t dev); 67 static int mambodisk_attach(device_t dev); 68 69 /* disk routines */ 70 static int mambodisk_open(struct disk *dp); 71 static int mambodisk_close(struct disk *dp); 72 static void mambodisk_strategy(struct bio *bp); 73 static void mambodisk_task(void *arg); 74 75 #define MBODISK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 76 #define MBODISK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 77 #define MBODISK_LOCK_INIT(_sc) \ 78 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 79 "mambodisk", MTX_DEF) 80 #define MBODISK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 81 #define MBODISK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 82 #define MBODISK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 83 84 static void 85 mambodisk_identify(driver_t *driver, device_t parent) 86 { 87 int i = 0; 88 89 for (i = 0; mambocall(MAMBO_DISK_INFO,MAMBO_INFO_DEVSZ,i) > 0; i++) 90 BUS_ADD_CHILD(parent,0,"mambodisk",i); 91 } 92 93 static int 94 mambodisk_probe(device_t dev) 95 { 96 device_set_desc(dev, "Mambo Simulated Block Device"); 97 return (0); 98 } 99 100 static int 101 mambodisk_attach(device_t dev) 102 { 103 struct mambodisk_softc *sc; 104 struct disk *d; 105 intmax_t mb; 106 char unit; 107 108 sc = device_get_softc(dev); 109 sc->dev = dev; 110 MBODISK_LOCK_INIT(sc); 111 112 d = sc->disk = disk_alloc(); 113 d->d_open = mambodisk_open; 114 d->d_close = mambodisk_close; 115 d->d_strategy = mambodisk_strategy; 116 d->d_name = "mambodisk"; 117 d->d_drv1 = sc; 118 d->d_maxsize = MAXPHYS; /* Maybe ask bridge? */ 119 120 d->d_sectorsize = 512; 121 sc->maxblocks = mambocall(MAMBO_DISK_INFO,MAMBO_INFO_BLKSZ,d->d_unit) 122 / 512; 123 124 d->d_unit = device_get_unit(dev); 125 d->d_mediasize = mambocall(MAMBO_DISK_INFO,MAMBO_INFO_DEVSZ,d->d_unit) 126 * 1024ULL; /* Mambo gives size in KB */ 127 128 mb = d->d_mediasize >> 20; /* 1MiB == 1 << 20 */ 129 unit = 'M'; 130 if (mb >= 10240) { /* 1GiB = 1024 MiB */ 131 unit = 'G'; 132 mb /= 1024; 133 } 134 device_printf(dev, "%ju%cB, %d byte sectors\n", mb, unit, 135 d->d_sectorsize); 136 disk_create(d, DISK_VERSION); 137 bioq_init(&sc->bio_queue); 138 139 sc->running = 1; 140 kproc_create(&mambodisk_task, sc, &sc->p, 0, 0, "task: mambo hd"); 141 142 return (0); 143 } 144 145 static int 146 mambodisk_detach(device_t dev) 147 { 148 struct mambodisk_softc *sc = device_get_softc(dev); 149 150 /* kill thread */ 151 MBODISK_LOCK(sc); 152 sc->running = 0; 153 wakeup(sc); 154 MBODISK_UNLOCK(sc); 155 156 /* wait for thread to finish. XXX probably want timeout. -sorbo */ 157 MBODISK_LOCK(sc); 158 while (sc->running != -1) 159 msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0); 160 MBODISK_UNLOCK(sc); 161 162 /* kill disk */ 163 disk_destroy(sc->disk); 164 /* XXX destroy anything in queue */ 165 166 MBODISK_LOCK_DESTROY(sc); 167 168 return (0); 169 } 170 171 static int 172 mambodisk_open(struct disk *dp) 173 { 174 return (0); 175 } 176 177 static int 178 mambodisk_close(struct disk *dp) 179 { 180 return (0); 181 } 182 183 static void 184 mambodisk_strategy(struct bio *bp) 185 { 186 struct mambodisk_softc *sc; 187 188 sc = (struct mambodisk_softc *)bp->bio_disk->d_drv1; 189 MBODISK_LOCK(sc); 190 bioq_disksort(&sc->bio_queue, bp); 191 wakeup(sc); 192 MBODISK_UNLOCK(sc); 193 } 194 195 static void 196 mambodisk_task(void *arg) 197 { 198 struct mambodisk_softc *sc = (struct mambodisk_softc*)arg; 199 struct bio *bp; 200 size_t sz; 201 int result; 202 daddr_t block, end; 203 device_t dev; 204 u_long unit; 205 206 dev = sc->dev; 207 unit = device_get_unit(dev); 208 209 while (sc->running) { 210 MBODISK_LOCK(sc); 211 do { 212 bp = bioq_first(&sc->bio_queue); 213 if (bp == NULL) 214 msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); 215 } while (bp == NULL && sc->running); 216 if (bp) 217 bioq_remove(&sc->bio_queue, bp); 218 MBODISK_UNLOCK(sc); 219 if (!sc->running) 220 break; 221 sz = sc->disk->d_sectorsize; 222 end = bp->bio_pblkno + (bp->bio_bcount / sz); 223 for (block = bp->bio_pblkno; block < end;) { 224 u_long numblocks; 225 char *vaddr = bp->bio_data + 226 (block - bp->bio_pblkno) * sz; 227 228 numblocks = end - block; 229 if (numblocks > sc->maxblocks) 230 numblocks = sc->maxblocks; 231 232 if (bp->bio_cmd == BIO_READ) { 233 result = mambocall(MAMBO_DISK_READ, vaddr, 234 (u_long)block, (numblocks << 16) | unit); 235 } else if (bp->bio_cmd == BIO_WRITE) { 236 result = mambocall(MAMBO_DISK_WRITE, vaddr, 237 (u_long)block, (numblocks << 16) | unit); 238 } else { 239 result = 1; 240 } 241 242 if (result) 243 break; 244 245 block += numblocks; 246 } 247 if (block < end) { 248 bp->bio_error = EIO; 249 bp->bio_resid = (end - block) * sz; 250 bp->bio_flags |= BIO_ERROR; 251 } 252 biodone(bp); 253 } 254 255 /* tell parent we're done */ 256 MBODISK_LOCK(sc); 257 sc->running = -1; 258 wakeup(sc); 259 MBODISK_UNLOCK(sc); 260 261 kproc_exit(0); 262 } 263 264 static device_method_t mambodisk_methods[] = { 265 DEVMETHOD(device_identify, mambodisk_identify), 266 DEVMETHOD(device_probe, mambodisk_probe), 267 DEVMETHOD(device_attach, mambodisk_attach), 268 DEVMETHOD(device_detach, mambodisk_detach), 269 {0, 0}, 270 }; 271 272 static driver_t mambodisk_driver = { 273 "mambodisk", 274 mambodisk_methods, 275 sizeof(struct mambodisk_softc), 276 }; 277 static devclass_t mambodisk_devclass; 278 279 DRIVER_MODULE(mambodisk, mambo, mambodisk_driver, mambodisk_devclass, 0, 0); 280