1/* $NetBSD: bmd.c,v 1.17 2010/08/08 09:30:29 isaki Exp $ */ 2 3/* 4 * Copyright (c) 2002 Tetsuya Isaki. 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, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28/* 29 * Nereid bank memory disk 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: bmd.c,v 1.17 2010/08/08 09:30:29 isaki Exp $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/buf.h> 38#include <sys/conf.h> 39#include <sys/device.h> 40#include <sys/kernel.h> 41#include <sys/stat.h> 42#include <sys/disk.h> 43#include <sys/disklabel.h> 44#include <sys/ioctl.h> 45#include <sys/fcntl.h> 46#include <sys/proc.h> 47 48#include <machine/bus.h> 49#include <machine/cpu.h> 50 51#include <arch/x68k/dev/intiovar.h> 52 53#define BMD_ADDR1 (0xece3f0) 54#define BMD_ADDR2 (0xecebf0) 55 56#define BMD_PAGESIZE (0x10000) /* 64KB */ 57#define BMD_BSIZE (512) 58#define BLKS_PER_PAGE (BMD_PAGESIZE / BMD_BSIZE) 59 60#define BMD_PAGE (0) 61#define BMD_CTRL (1) 62#define BMD_CTRL_ENABLE (0x80) /* DIP8: 1=Enable, 0=Disable */ 63#define BMD_CTRL_MEMORY (0x40) /* 1=16M available, 0=4M available */ 64#define BMD_CTRL_WINDOW (0x20) /* DIP6: 1=0xee0000, 0=0xef0000 */ 65 66 67#define BMD_UNIT(dev) (minor(dev) / 8) 68 69#ifdef BMD_DEBUG 70#define DPRINTF(x) printf x 71#else 72#define DPRINTF(x) /* nothing */ 73#endif 74 75struct bmd_softc { 76 struct disk sc_dkdev; 77 bus_space_tag_t sc_iot; 78 bus_space_handle_t sc_ioh; 79 bus_space_handle_t sc_bank; 80 81 int sc_maxpage; 82 int sc_window; 83 84 int sc_flags; 85#define BMD_OPENBLK (0x01) 86#define BMD_OPENCHR (0x02) 87#define BMD_OPEN (BMD_OPENBLK | BMD_OPENCHR) 88}; 89 90static int bmd_match(device_t, cfdata_t, void *); 91static void bmd_attach(device_t, device_t, void *); 92static int bmd_getdisklabel(struct bmd_softc *, dev_t); 93 94extern struct cfdriver bmd_cd; 95 96CFATTACH_DECL_NEW(bmd, sizeof(struct bmd_softc), 97 bmd_match, bmd_attach, NULL, NULL); 98 99dev_type_open(bmdopen); 100dev_type_close(bmdclose); 101dev_type_read(bmdread); 102dev_type_write(bmdwrite); 103dev_type_ioctl(bmdioctl); 104dev_type_strategy(bmdstrategy); 105dev_type_dump(bmddump); 106dev_type_size(bmdsize); 107 108const struct bdevsw bmd_bdevsw = { 109 bmdopen, bmdclose, bmdstrategy, bmdioctl, bmddump, bmdsize, D_DISK 110}; 111 112const struct cdevsw bmd_cdevsw = { 113 bmdopen, bmdclose, bmdread, bmdwrite, bmdioctl, 114 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 115}; 116 117struct dkdriver bmddkdriver = { bmdstrategy }; 118 119static int 120bmd_match(device_t parent, cfdata_t cf, void *aux) 121{ 122 struct intio_attach_args *ia = aux; 123 bus_space_tag_t iot = ia->ia_bst; 124 bus_space_handle_t ioh; 125 int window; 126 int r; 127 128 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT) 129 ia->ia_addr = BMD_ADDR1; 130 131 /* fixed parameter */ 132 if (ia->ia_addr != BMD_ADDR1 && ia->ia_addr != BMD_ADDR2) 133 return (0); 134 135 /* Check CTRL addr */ 136 if (badaddr((void *)IIOV(ia->ia_addr))) 137 return (0); 138 139 ia->ia_size = 2; 140 if (bus_space_map(iot, ia->ia_addr, ia->ia_size, 0, &ioh)) 141 return (0); 142 143 /* Check window addr */ 144 r = bus_space_read_1(iot, ioh, BMD_CTRL); 145 bus_space_unmap(iot, ioh, ia->ia_size); 146 147 if ((r & BMD_CTRL_WINDOW)) 148 window = 0xef0000; 149 else 150 window = 0xee0000; 151 if (badaddr((void *)IIOV(window))) 152 return (0); 153 154 return (1); 155} 156 157static void 158bmd_attach(device_t parent, device_t self, void *aux) 159{ 160 struct bmd_softc *sc = device_private(self); 161 struct intio_attach_args *ia = aux; 162 bus_space_tag_t iot = ia->ia_bst; 163 bus_space_handle_t ioh; 164 u_int8_t r; 165 166 aprint_normal(": Nereid Bank Memory Disk\n"); 167 168 /* Map I/O space */ 169 ia->ia_size = 2; 170 if (bus_space_map(iot, ia->ia_addr, ia->ia_size, 0, &ioh)) { 171 aprint_error_dev(self, "can't map I/O space\n"); 172 return; 173 } 174 175 sc->sc_iot = iot; 176 sc->sc_ioh = ioh; 177 178 /* read control register */ 179 r = bus_space_read_1(sc->sc_iot, sc->sc_ioh, BMD_CTRL); 180 181 /* check enable-bit */ 182 if ((r & BMD_CTRL_ENABLE) == 0) { 183 aprint_error_dev(self, "disabled by DIP-SW 8\n"); 184 return; 185 } 186 187 if ((r & BMD_CTRL_MEMORY)) 188 sc->sc_maxpage = 256; 189 else 190 sc->sc_maxpage = 64; 191 192 if ((r & BMD_CTRL_WINDOW)) 193 sc->sc_window = 0xef0000; 194 else 195 sc->sc_window = 0xee0000; 196 197 /* Map bank area */ 198 if (bus_space_map(iot, sc->sc_window, BMD_PAGESIZE, 0, &sc->sc_bank)) { 199 aprint_error_dev(self, "can't map bank area: 0x%x\n", 200 sc->sc_window); 201 return; 202 } 203 204 aprint_normal_dev(self, "%d MB, 0x%x(64KB) x %d pages\n", 205 (sc->sc_maxpage / 16), sc->sc_window, sc->sc_maxpage); 206 207 disk_init(&sc->sc_dkdev, device_xname(self), &bmddkdriver); 208 disk_attach(&sc->sc_dkdev); 209} 210 211int 212bmdopen(dev_t dev, int oflags, int devtype, struct lwp *l) 213{ 214 struct bmd_softc *sc; 215 216 DPRINTF(("%s%d\n", __func__, unit)); 217 218 sc = device_lookup_private(&bmd_cd, BMD_UNIT(dev)); 219 if (sc == NULL) 220 return ENXIO; 221 222 switch (devtype) { 223 case S_IFCHR: 224 sc->sc_flags |= BMD_OPENCHR; 225 break; 226 case S_IFBLK: 227 sc->sc_flags |= BMD_OPENBLK; 228 break; 229 } 230 231 bmd_getdisklabel(sc, dev); 232 233 return (0); 234} 235 236int 237bmdclose(dev_t dev, int fflag, int devtype, struct lwp *l) 238{ 239 struct bmd_softc *sc = device_lookup_private(&bmd_cd, BMD_UNIT(dev)); 240 241 DPRINTF(("%s%d\n", __func__, BMD_UNIT(dev))); 242 243 switch (devtype) { 244 case S_IFCHR: 245 sc->sc_flags &= ~BMD_OPENCHR; 246 break; 247 case S_IFBLK: 248 sc->sc_flags &= ~BMD_OPENBLK; 249 break; 250 } 251 252 return (0); 253} 254 255void 256bmdstrategy(struct buf *bp) 257{ 258 int unit = BMD_UNIT(bp->b_dev); 259 struct bmd_softc *sc; 260 int offset, disksize, resid; 261 int page, pg_offset, pg_resid; 262 void *data; 263 264 if (unit >= bmd_cd.cd_ndevs) { 265 bp->b_error = ENXIO; 266 goto done; 267 } 268 269 sc = device_lookup_private(&bmd_cd, BMD_UNIT(bp->b_dev)); 270 if (sc == NULL) { 271 bp->b_error = ENXIO; 272 goto done; 273 } 274 275 DPRINTF(("bmdstrategy: %s blkno %d bcount %ld:", 276 (bp->b_flags & B_READ) ? "read " : "write", 277 bp->b_blkno, bp->b_bcount)); 278 279 bp->b_resid = bp->b_bcount; 280 offset = (bp->b_blkno << DEV_BSHIFT); 281 disksize = sc->sc_maxpage * BMD_PAGESIZE; 282 if (offset >= disksize) { 283 /* EOF if read, EIO if write */ 284 if (bp->b_flags & B_READ) 285 goto done; 286 bp->b_error = EIO; 287 goto done; 288 } 289 290 resid = bp->b_resid; 291 if (resid > disksize - offset) 292 resid = disksize - offset; 293 294 data = bp->b_data; 295 do { 296 page = offset / BMD_PAGESIZE; 297 pg_offset = offset % BMD_PAGESIZE; 298 299 /* length */ 300 pg_resid = MIN(resid, BMD_PAGESIZE - pg_offset); 301 302 /* switch bank page */ 303 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BMD_PAGE, page); 304 305 /* XXX we should use DMA transfer? */ 306 if ((bp->b_flags & B_READ)) { 307 bus_space_read_region_1(sc->sc_iot, sc->sc_bank, 308 pg_offset, data, pg_resid); 309 } else { 310 bus_space_write_region_1(sc->sc_iot, sc->sc_bank, 311 pg_offset, data, pg_resid); 312 } 313 314 data = (char *)data + pg_resid; 315 offset += pg_resid; 316 resid -= pg_resid; 317 bp->b_resid -= pg_resid; 318 } while (resid > 0); 319 320 DPRINTF(("\n")); 321 322 done: 323 biodone(bp); 324} 325 326int 327bmdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 328{ 329 struct bmd_softc *sc; 330 struct disklabel dl; 331 int error; 332 333 DPRINTF(("%s%d %ld\n", __func__, BMD_UNIT(dev), cmd)); 334 335 sc = device_lookup_private(&bmd_cd, BMD_UNIT(dev)); 336 if (sc == NULL) 337 return ENXIO; 338 339 switch (cmd) { 340 case DIOCGDINFO: 341 *(struct disklabel *)data = *(sc->sc_dkdev.dk_label); 342 break; 343 344 case DIOCWDINFO: 345 if ((flag & FWRITE) == 0) 346 return EBADF; 347 348 error = setdisklabel(&dl, (struct disklabel *)data, 0, NULL); 349 if (error) 350 return error; 351 error = writedisklabel(dev, bmdstrategy, &dl, NULL); 352 return error; 353 354 default: 355 return EINVAL; 356 } 357 return 0; 358} 359 360int 361bmddump(dev_t dev, daddr_t blkno, void *va, size_t size) 362{ 363 364 DPRINTF(("%s%d ", __func__, BMD_UNIT(dev))); 365 return ENODEV; 366} 367 368int 369bmdsize(dev_t dev) 370{ 371 struct bmd_softc *sc; 372 373 DPRINTF(("%s%d ", __func__, BMD_UNIT(dev))); 374 375 sc = device_lookup_private(&bmd_cd, BMD_UNIT(dev)); 376 if (sc == NULL) 377 return 0; 378 379 return (sc->sc_maxpage * BMD_PAGESIZE) >> DEV_BSHIFT; 380} 381 382int 383bmdread(dev_t dev, struct uio *uio, int ioflag) 384{ 385 return physio(bmdstrategy, NULL, dev, B_READ, minphys, uio); 386} 387 388int 389bmdwrite(dev_t dev, struct uio *uio, int ioflag) 390{ 391 return physio(bmdstrategy, NULL, dev, B_WRITE, minphys, uio); 392} 393 394static int 395bmd_getdisklabel(struct bmd_softc *sc, dev_t dev) 396{ 397 struct disklabel *lp; 398 int part; 399 400 part = DISKPART(dev); 401 lp = sc->sc_dkdev.dk_label; 402 memset(lp, 0, sizeof(struct disklabel)); 403 404 lp->d_secsize = BMD_BSIZE; 405 lp->d_nsectors = BLKS_PER_PAGE; 406 lp->d_ntracks = sc->sc_maxpage; 407 lp->d_ncylinders = 1; 408 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 409 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 410 411 lp->d_type = DTYPE_LD; 412 lp->d_rpm = 300; /* dummy */ 413 lp->d_interleave = 1; /* dummy? */ 414 415 lp->d_npartitions = part + 1; 416 lp->d_bbsize = 8192; 417 lp->d_sbsize = 8192; /* ? */ 418 419 lp->d_magic = DISKMAGIC; 420 lp->d_magic2 = DISKMAGIC; 421 lp->d_checksum = dkcksum(lp); 422 423 lp->d_partitions[part].p_size = lp->d_secperunit; 424 lp->d_partitions[part].p_fstype = FS_BSDFFS; 425 lp->d_partitions[part].p_fsize = 1024; 426 lp->d_partitions[part].p_frag = 8; 427 428 return (0); 429} 430