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