1d9611800SBenno Rice /* 2d9611800SBenno Rice * Copyright (C) 2002 Benno Rice <benno@FreeBSD.org> 3d9611800SBenno Rice * All rights reserved. 4d9611800SBenno Rice * 5d9611800SBenno Rice * Redistribution and use in source and binary forms, with or without 6d9611800SBenno Rice * modification, are permitted provided that the following conditions 7d9611800SBenno Rice * are met: 8d9611800SBenno Rice * 1. Redistributions of source code must retain the above copyright 9d9611800SBenno Rice * notice, this list of conditions and the following disclaimer. 10d9611800SBenno Rice * 2. Redistributions in binary form must reproduce the above copyright 11d9611800SBenno Rice * notice, this list of conditions and the following disclaimer in the 12d9611800SBenno Rice * documentation and/or other materials provided with the distribution. 13d9611800SBenno Rice * 14d9611800SBenno Rice * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15d9611800SBenno Rice * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16d9611800SBenno Rice * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17d9611800SBenno Rice * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18d9611800SBenno Rice * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19d9611800SBenno Rice * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20d9611800SBenno Rice * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21d9611800SBenno Rice * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22d9611800SBenno Rice * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23d9611800SBenno Rice * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24d9611800SBenno Rice * 25d9611800SBenno Rice * $FreeBSD$ 26d9611800SBenno Rice * 27d9611800SBenno Rice */ 28d9611800SBenno Rice 29d9611800SBenno Rice #include <sys/param.h> 30d9611800SBenno Rice #include <sys/systm.h> 31d9611800SBenno Rice #include <sys/bio.h> 32d9611800SBenno Rice #include <sys/bus.h> 33d9611800SBenno Rice #include <sys/conf.h> 34d9611800SBenno Rice #include <sys/disk.h> 35d9611800SBenno Rice #include <sys/kernel.h> 36d9611800SBenno Rice 37d9611800SBenno Rice #include <dev/ofw/openfirm.h> 38d9611800SBenno Rice 39d9611800SBenno Rice #include <machine/bus.h> 40d9611800SBenno Rice #include <machine/md_var.h> 41d9611800SBenno Rice #include <machine/nexusvar.h> 42d9611800SBenno Rice 43d9611800SBenno Rice #define OFWD_BLOCKSIZE 512 44d9611800SBenno Rice 45d9611800SBenno Rice struct ofwd_softc 46d9611800SBenno Rice { 47d9611800SBenno Rice device_t ofwd_dev; 48d9611800SBenno Rice dev_t ofwd_dev_t; 49d9611800SBenno Rice struct disk ofwd_disk; 50d9611800SBenno Rice phandle_t ofwd_package; 51d9611800SBenno Rice ihandle_t ofwd_instance; 52d9611800SBenno Rice u_int ofwd_flags; 53d9611800SBenno Rice #define OFWD_OPEN (1<<0) 54d9611800SBenno Rice }; 55d9611800SBenno Rice 56d9611800SBenno Rice /* 57d9611800SBenno Rice * Disk device bus interface. 58d9611800SBenno Rice */ 59d9611800SBenno Rice static void ofwd_identify(driver_t *, device_t); 60d9611800SBenno Rice static int ofwd_probe(device_t); 61d9611800SBenno Rice static int ofwd_attach(device_t); 62d9611800SBenno Rice 63d9611800SBenno Rice static device_method_t ofwd_methods[] = { 64d9611800SBenno Rice DEVMETHOD(device_identify, ofwd_identify), 65d9611800SBenno Rice DEVMETHOD(device_probe, ofwd_probe), 66d9611800SBenno Rice DEVMETHOD(device_attach, ofwd_attach), 67d9611800SBenno Rice { 0, 0 } 68d9611800SBenno Rice }; 69d9611800SBenno Rice 70d9611800SBenno Rice static driver_t ofwd_driver = { 71d9611800SBenno Rice "ofwd", 72d9611800SBenno Rice ofwd_methods, 73d9611800SBenno Rice sizeof(struct ofwd_softc) 74d9611800SBenno Rice }; 75d9611800SBenno Rice 76d9611800SBenno Rice static devclass_t ofwd_devclass; 77d9611800SBenno Rice 78d9611800SBenno Rice DRIVER_MODULE(ofwd, nexus, ofwd_driver, ofwd_devclass, 0, 0); 79d9611800SBenno Rice 80d9611800SBenno Rice /* 81d9611800SBenno Rice * Disk device control interface. 82d9611800SBenno Rice */ 83d9611800SBenno Rice static d_open_t ofwd_open; 84d9611800SBenno Rice static d_close_t ofwd_close; 85d9611800SBenno Rice static d_strategy_t ofwd_strategy; 86d9611800SBenno Rice 87d9611800SBenno Rice #define OFWD_CDEV_MAJOR 169 88d9611800SBenno Rice 89d9611800SBenno Rice static struct cdevsw ofwd_cdevsw = { 90d9611800SBenno Rice ofwd_open, 91d9611800SBenno Rice ofwd_close, 92d9611800SBenno Rice physread, 93d9611800SBenno Rice physwrite, 94d9611800SBenno Rice noioctl, 95d9611800SBenno Rice nopoll, 96d9611800SBenno Rice nommap, 97d9611800SBenno Rice ofwd_strategy, 98d9611800SBenno Rice "ofwd", 99d9611800SBenno Rice OFWD_CDEV_MAJOR, 100d9611800SBenno Rice nodump, 101d9611800SBenno Rice nopsize, 102d9611800SBenno Rice D_DISK 103d9611800SBenno Rice }; 104d9611800SBenno Rice 105d9611800SBenno Rice static struct cdevsw ofwddisk_cdevsw; 106d9611800SBenno Rice 107d9611800SBenno Rice /* 108d9611800SBenno Rice * Handle open from generic layer. 109d9611800SBenno Rice * 110d9611800SBenno Rice * This is typically only called by the diskslice code and not for opens on 111d9611800SBenno Rice * subdevices. 112d9611800SBenno Rice */ 113d9611800SBenno Rice static int 114d9611800SBenno Rice ofwd_open(dev_t dev, int flags, int fmt, struct thread *td) 115d9611800SBenno Rice { 116d9611800SBenno Rice struct ofwd_softc *sc; 117d9611800SBenno Rice struct disklabel *label; 118d9611800SBenno Rice 119d9611800SBenno Rice sc = (struct ofwd_softc *)dev->si_drv1; 120d9611800SBenno Rice if (sc == NULL) 121d9611800SBenno Rice return (ENXIO); 122d9611800SBenno Rice 123d9611800SBenno Rice /* 124d9611800SBenno Rice * Build synthetic label. 125d9611800SBenno Rice */ 126d9611800SBenno Rice label = &sc->ofwd_disk.d_label; 127d9611800SBenno Rice bzero(label, sizeof(*label)); 128d9611800SBenno Rice label->d_type = DTYPE_ESDI; 129d9611800SBenno Rice label->d_secsize = OFWD_BLOCKSIZE; 130d9611800SBenno Rice label->d_nsectors = 33554432; 131d9611800SBenno Rice label->d_ntracks = 1; 132d9611800SBenno Rice label->d_ncylinders = 1024; 133d9611800SBenno Rice label->d_secpercyl = 32768; 134d9611800SBenno Rice label->d_secperunit = 33554432; 135d9611800SBenno Rice 136d9611800SBenno Rice sc->ofwd_flags |= OFWD_OPEN; 137d9611800SBenno Rice return (0); 138d9611800SBenno Rice } 139d9611800SBenno Rice 140d9611800SBenno Rice /* 141d9611800SBenno Rice * Handle last close of the disk device. 142d9611800SBenno Rice */ 143d9611800SBenno Rice static int 144d9611800SBenno Rice ofwd_close(dev_t dev, int flags, int fmt, struct thread *td) 145d9611800SBenno Rice { 146d9611800SBenno Rice struct ofwd_softc *sc; 147d9611800SBenno Rice 148d9611800SBenno Rice sc = (struct ofwd_softc *)dev->si_drv1; 149d9611800SBenno Rice 150d9611800SBenno Rice if (sc == NULL) 151d9611800SBenno Rice return (ENXIO); 152d9611800SBenno Rice 153d9611800SBenno Rice sc->ofwd_flags &= ~OFWD_OPEN; 154d9611800SBenno Rice 155d9611800SBenno Rice return (0); 156d9611800SBenno Rice } 157d9611800SBenno Rice 158d9611800SBenno Rice /* 159d9611800SBenno Rice * Handle an I/O request. 160d9611800SBenno Rice */ 161d9611800SBenno Rice static void 162d9611800SBenno Rice ofwd_strategy(struct bio *bp) 163d9611800SBenno Rice { 164d9611800SBenno Rice struct ofwd_softc *sc; 165d9611800SBenno Rice long r; 166d9611800SBenno Rice 167d9611800SBenno Rice sc = (struct ofwd_softc *)bp->bio_dev->si_drv1; 168d9611800SBenno Rice 169d9611800SBenno Rice if (sc == NULL) { 170d9611800SBenno Rice bp->bio_error = EINVAL; 171d9611800SBenno Rice bp->bio_flags |= BIO_ERROR; 172d9611800SBenno Rice printf("ofwd: bio for invalid disk!\n"); 173d9611800SBenno Rice biodone(bp); 174d9611800SBenno Rice return; 175d9611800SBenno Rice } 176d9611800SBenno Rice 177d9611800SBenno Rice r = OF_seek(sc->ofwd_instance, 178d9611800SBenno Rice (u_quad_t)(bp->bio_blkno * OFWD_BLOCKSIZE)); 179d9611800SBenno Rice if (r == -1) { 180d9611800SBenno Rice bp->bio_resid = bp->bio_bcount; 181d9611800SBenno Rice bp->bio_error = EIO; 182d9611800SBenno Rice bp->bio_flags |= BIO_ERROR; 183d9611800SBenno Rice device_printf(sc->ofwd_dev, "seek failed\n"); 184d9611800SBenno Rice biodone(bp); 185d9611800SBenno Rice return; 186d9611800SBenno Rice } 187d9611800SBenno Rice 188d9611800SBenno Rice if (bp->bio_cmd == BIO_READ) { 189d9611800SBenno Rice r = OF_read(sc->ofwd_instance, (void *)bp->bio_data, 190d9611800SBenno Rice bp->bio_bcount); 191d9611800SBenno Rice } else { 192d9611800SBenno Rice r = OF_write(sc->ofwd_instance, (void *)bp->bio_data, 193d9611800SBenno Rice bp->bio_bcount); 194d9611800SBenno Rice } 195d9611800SBenno Rice 196d9611800SBenno Rice if (r < bp->bio_bcount) { 197d9611800SBenno Rice device_printf(sc->ofwd_dev, "r (%ld) < bp->bio_bcount (%ld)\n", 198d9611800SBenno Rice r, bp->bio_bcount); 199d9611800SBenno Rice if (r != -1) 200d9611800SBenno Rice bp->bio_resid = bp->bio_bcount - r; 201d9611800SBenno Rice bp->bio_error = EIO; 202d9611800SBenno Rice bp->bio_flags |= BIO_ERROR; 203d9611800SBenno Rice } else if (r > bp->bio_bcount) 204d9611800SBenno Rice panic("ofwd: more bytes read/written than requested"); 205d9611800SBenno Rice 206d9611800SBenno Rice bp->bio_resid -= r; 207d9611800SBenno Rice biodone(bp); 208d9611800SBenno Rice 209d9611800SBenno Rice return; 210d9611800SBenno Rice } 211d9611800SBenno Rice 212d9611800SBenno Rice /* 213d9611800SBenno Rice * Probe for an OpenFirmware disk. 214d9611800SBenno Rice */ 215d9611800SBenno Rice static int 216d9611800SBenno Rice ofwd_probe(device_t dev) 217d9611800SBenno Rice { 218d9611800SBenno Rice char *type; 219d9611800SBenno Rice 220d9611800SBenno Rice type = nexus_get_device_type(dev); 221d9611800SBenno Rice 222d9611800SBenno Rice if (type == NULL || strcmp(type, "disk") != 0) 223d9611800SBenno Rice return (ENXIO); 224d9611800SBenno Rice 225d9611800SBenno Rice device_set_desc(dev, "OpenFirmware disk"); 226d9611800SBenno Rice return (0); 227d9611800SBenno Rice } 228d9611800SBenno Rice 229d9611800SBenno Rice static int 230d9611800SBenno Rice ofwd_attach(device_t dev) 231d9611800SBenno Rice { 232d9611800SBenno Rice struct ofwd_softc *sc; 233d9611800SBenno Rice char path[128]; 234d9611800SBenno Rice dev_t dsk; 235d9611800SBenno Rice 236d9611800SBenno Rice sc = device_get_softc(dev); 237d9611800SBenno Rice sc->ofwd_dev = dev; 238d9611800SBenno Rice 239d9611800SBenno Rice bzero(path, 128); 240d9611800SBenno Rice OF_package_to_path(nexus_get_node(dev), path, 128); 241d9611800SBenno Rice device_printf(dev, "located at %s\n", path); 242d9611800SBenno Rice sc->ofwd_instance = OF_open(path); 243d9611800SBenno Rice if (sc->ofwd_instance == -1) { 244d9611800SBenno Rice device_printf(dev, "could not create instance\n"); 245d9611800SBenno Rice return (ENXIO); 246d9611800SBenno Rice } 247d9611800SBenno Rice 248d9611800SBenno Rice dsk = disk_create(device_get_unit(dev), &sc->ofwd_disk, 0, 249d9611800SBenno Rice &ofwd_cdevsw, &ofwddisk_cdevsw); 250d9611800SBenno Rice dsk->si_drv1 = sc; 251d9611800SBenno Rice sc->ofwd_dev_t = dsk; 252d9611800SBenno Rice 253d9611800SBenno Rice dsk->si_iosize_max = PAGE_SIZE; 254d9611800SBenno Rice 255d9611800SBenno Rice return (0); 256d9611800SBenno Rice } 257d9611800SBenno Rice 258d9611800SBenno Rice static void 259d9611800SBenno Rice ofwd_identify(driver_t *driver, device_t parent) 260d9611800SBenno Rice { 261d9611800SBenno Rice } 262