d4ebee28d2
Sponsored by: M-systems Inc. http://www.m-sys.com
452 lines
8.6 KiB
C
452 lines
8.6 KiB
C
/*
|
|
* ----------------------------------------------------------------------------
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
|
|
* can do whatever you want with this stuff. If we meet some day, and you think
|
|
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* $Id: fla.c,v 1.3 1999/08/06 15:22:09 phk Exp $
|
|
*
|
|
*/
|
|
|
|
#include "fla.h"
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/disklabel.h>
|
|
#include <sys/diskslice.h>
|
|
#include <sys/module.h>
|
|
#include <sys/conf.h>
|
|
#include <machine/bus.h>
|
|
#include <machine/clock.h>
|
|
#include <machine/resource.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/pmap.h>
|
|
#include <vm/vm_param.h>
|
|
|
|
#if __FreeBSD_version > 400000 /* XXX ? */
|
|
#include <sys/bus.h>
|
|
#include <isa/isareg.h>
|
|
#include <isa/isavar.h>
|
|
|
|
#define dev2ul(foo) ((unsigned long)dev2udev(foo))
|
|
#endif
|
|
|
|
#if __FreeBSD_version < 400000 /* XXX ? */
|
|
#include <i386/isa/isa_device.h>
|
|
|
|
#define dev2ul(foo) ((unsigned long)foo)
|
|
|
|
static int
|
|
physread(dev_t dev, struct uio *uio, int ioflag)
|
|
{
|
|
return(physio(cdevsw[major(dev)]->d_strategy,
|
|
NULL, dev, 1, minphys, uio));
|
|
}
|
|
|
|
static int
|
|
physwrite(dev_t dev, struct uio *uio, int ioflag)
|
|
{
|
|
return(physio(cdevsw[major(dev)]->d_strategy,
|
|
NULL, dev, 0, minphys, uio));
|
|
}
|
|
|
|
#define nopoll seltrue
|
|
#define noparms NULL
|
|
#endif
|
|
|
|
#include <../../contrib/dev/fla/msysosak.h>
|
|
|
|
MALLOC_DEFINE(M_FLA, "fla driver", "fla driver storage");
|
|
|
|
static int fla_debug = 0;
|
|
SYSCTL_INT(_debug, OID_AUTO, fladebug, CTLFLAG_RW, &fla_debug, 0, "");
|
|
|
|
#define CDEV_MAJOR 102
|
|
#define BDEV_MAJOR 28
|
|
|
|
static d_strategy_t flastrategy;
|
|
static d_open_t flaopen;
|
|
static d_close_t flaclose;
|
|
static d_ioctl_t flaioctl;
|
|
static d_psize_t flapsize;
|
|
|
|
static struct cdevsw fla_cdevsw = {
|
|
/* open */ flaopen,
|
|
/* close */ flaclose,
|
|
/* read */ physread,
|
|
/* write */ physwrite,
|
|
/* ioctl */ flaioctl,
|
|
/* stop */ nostop,
|
|
/* reset */ noreset,
|
|
/* devtotty */ nodevtotty,
|
|
/* poll */ nopoll,
|
|
/* mmap */ nommap,
|
|
/* strategy */ flastrategy,
|
|
/* name */ "fla",
|
|
/* parms */ noparms,
|
|
/* maj */ CDEV_MAJOR,
|
|
/* dump */ nodump,
|
|
/* psize */ flapsize,
|
|
/* flags */ D_DISK | D_CANFREE,
|
|
/* maxio */ 0,
|
|
/* bmaj */ BDEV_MAJOR
|
|
};
|
|
|
|
|
|
|
|
void *
|
|
doc2k_malloc(int bytes)
|
|
{
|
|
return malloc(bytes, M_FLA, M_WAITOK);
|
|
}
|
|
|
|
void
|
|
doc2k_free(void *ptr)
|
|
{
|
|
free(ptr, M_FLA);
|
|
}
|
|
|
|
void
|
|
doc2k_delay(unsigned msec)
|
|
{
|
|
DELAY(1000 * msec);
|
|
}
|
|
|
|
void
|
|
doc2k_memcpy(void *dst, const void *src, unsigned len)
|
|
{
|
|
bcopy(src, dst, len);
|
|
}
|
|
|
|
int
|
|
doc2k_memcmp(const void *dst, const void *src, unsigned len)
|
|
{
|
|
return (bcmp(src, dst, len));
|
|
}
|
|
|
|
void
|
|
doc2k_memset(void *dst, int c, unsigned len)
|
|
{
|
|
u_char *p = dst;
|
|
while (len--)
|
|
*p++ = c;
|
|
}
|
|
|
|
static struct fla_s {
|
|
unsigned nsect;
|
|
struct doc2k_stat ds;
|
|
struct diskslices *dk_slices;
|
|
struct buf_queue_head buf_queue;
|
|
} softc[NFLA];
|
|
|
|
static int
|
|
flaopen(dev_t dev, int flag, int fmt, struct proc *p)
|
|
{
|
|
int unit;
|
|
struct fla_s *sc;
|
|
int error;
|
|
struct disklabel dk_dd;
|
|
|
|
if (fla_debug)
|
|
printf("flaopen(%lx %x %x %p)\n",
|
|
dev2ul(dev), flag, fmt, p);
|
|
unit = dkunit(dev);
|
|
if (unit >= NFLA)
|
|
return (ENXIO);
|
|
sc = &softc[unit];
|
|
if (!sc->nsect)
|
|
return (ENXIO);
|
|
bzero(&dk_dd, sizeof(dk_dd));
|
|
error = doc2k_size(unit, &dk_dd.d_secperunit,
|
|
&dk_dd.d_ncylinders, &dk_dd.d_ntracks, &dk_dd.d_nsectors);
|
|
dk_dd.d_secsize = DEV_BSIZE;
|
|
dk_dd.d_secpercyl = dk_dd.d_ntracks * dk_dd.d_nsectors;
|
|
|
|
error = dsopen("fla", dev, fmt, 0, &sc->dk_slices, &dk_dd,
|
|
flastrategy, NULL, &fla_cdevsw);
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
flaclose(dev_t dev, int flags, int fmt, struct proc *p)
|
|
{
|
|
int unit;
|
|
struct fla_s *sc;
|
|
|
|
if (fla_debug)
|
|
printf("flaclose(%lx %x %x %p)\n",
|
|
dev2ul(dev), flags, fmt, p);
|
|
unit = dkunit(dev);
|
|
sc = &softc[unit];
|
|
dsclose(dev, fmt, sc->dk_slices);
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
flaioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
|
|
{
|
|
int unit, error;
|
|
struct fla_s *sc;
|
|
|
|
if (fla_debug)
|
|
printf("flaioctl(%lx %lx %p %x %p)\n",
|
|
dev2ul(dev), cmd, addr, flags, p);
|
|
unit = dkunit(dev);
|
|
sc = &softc[unit];
|
|
error = dsioctl("fla", dev, cmd, addr, flags, &sc->dk_slices,
|
|
flastrategy, NULL);
|
|
if (error == ENOIOCTL)
|
|
error = ENOTTY;
|
|
return (error);
|
|
}
|
|
|
|
static void
|
|
flastrategy(struct buf *bp)
|
|
{
|
|
int unit, error;
|
|
u_long ef;
|
|
struct fla_s *sc;
|
|
static int busy;
|
|
enum doc2k_work what;
|
|
|
|
if (fla_debug)
|
|
printf("flastrategy(%p) %lx %lx, %d, %ld, %p)\n",
|
|
bp, dev2ul(bp->b_dev), bp->b_flags, bp->b_blkno,
|
|
bp->b_bcount / DEV_BSIZE, bp->b_data);
|
|
unit = dkunit(bp->b_dev);
|
|
sc = &softc[unit];
|
|
|
|
if (dscheck(bp, sc->dk_slices) <= 0) {
|
|
biodone(bp);
|
|
return;
|
|
}
|
|
|
|
ef = read_eflags();
|
|
disable_intr();
|
|
|
|
bufqdisksort(&sc->buf_queue, bp);
|
|
|
|
if (busy) {
|
|
write_eflags(ef);
|
|
return;
|
|
}
|
|
|
|
busy++;
|
|
|
|
while (1) {
|
|
bp = bufq_first(&sc->buf_queue);
|
|
if (bp)
|
|
bufq_remove(&sc->buf_queue, bp);
|
|
|
|
write_eflags(ef);
|
|
if (!bp)
|
|
break;
|
|
|
|
bp->b_resid = bp->b_bcount;
|
|
unit = dkunit(bp->b_dev);
|
|
|
|
if (bp->b_flags & B_FREEBUF)
|
|
what = DOC2K_ERASE;
|
|
else if (bp->b_flags & B_READ)
|
|
what = DOC2K_READ;
|
|
else
|
|
what = DOC2K_WRITE;
|
|
|
|
error = doc2k_rwe( unit, what, bp->b_pblkno,
|
|
bp->b_bcount / DEV_BSIZE, bp->b_data);
|
|
|
|
if (fla_debug || error) {
|
|
printf("fla%d: %d = rwe(%p, %d, %d, %d, %ld, %p)\n",
|
|
unit, error, bp, unit, what, bp->b_pblkno,
|
|
bp->b_bcount / DEV_BSIZE, bp->b_data);
|
|
}
|
|
if (error) {
|
|
bp->b_error = EIO;
|
|
bp->b_flags |= B_ERROR;
|
|
} else {
|
|
bp->b_resid = 0;
|
|
}
|
|
biodone(bp);
|
|
|
|
ef = read_eflags();
|
|
disable_intr();
|
|
}
|
|
busy = 0;
|
|
return;
|
|
}
|
|
|
|
static int
|
|
flapsize(dev_t dev)
|
|
{
|
|
int unit;
|
|
struct fla_s *sc;
|
|
|
|
if (fla_debug)
|
|
printf("flapsize(%lx)\n", dev2ul(dev));
|
|
unit = dkunit(dev);
|
|
sc = &softc[unit];
|
|
if (!sc->nsect)
|
|
return 0;
|
|
|
|
return (dssize(dev, &sc->dk_slices, flaopen, flaclose));
|
|
}
|
|
|
|
static int
|
|
flarealprobe(int unit)
|
|
{
|
|
struct fla_s *sc;
|
|
int i;
|
|
|
|
sc = &softc[unit];
|
|
|
|
/* This is slightly ugly */
|
|
i = doc2k_probe(unit, KERNBASE + 0xc0000, KERNBASE + 0xe0000);
|
|
if (i)
|
|
return (ENXIO);
|
|
|
|
i = doc2k_info(unit, &sc->ds);
|
|
if (i)
|
|
return (ENXIO);
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
static int
|
|
flarealattach(int unit)
|
|
{
|
|
int i, j, k, l, m, error;
|
|
struct fla_s *sc;
|
|
|
|
sc = &softc[unit];
|
|
|
|
error = doc2k_open(unit);
|
|
if (error) {
|
|
printf("doc2k_open(%d) -> err %d\n", unit, error);
|
|
return (EIO);
|
|
}
|
|
|
|
error = doc2k_size(unit, &sc->nsect, &i, &j, &k );
|
|
if (error) {
|
|
printf("doc2k_size(%d) -> err %d\n", unit, error);
|
|
return (EIO);
|
|
}
|
|
|
|
printf("fla%d: <%s %s>\n", unit, sc->ds.product, sc->ds.model);
|
|
|
|
m = 1024L * 1024L / DEV_BSIZE;
|
|
l = (sc->nsect * 10 + m/2) / m;
|
|
printf("fla%d: %d.%01dMB (%u sectors),"
|
|
" %d cyls, %d heads, %d S/T, 512 B/S\n",
|
|
unit, l / 10, l % 10, sc->nsect, i, j, k);
|
|
|
|
if (bootverbose)
|
|
printf("fla%d: JEDEC=0x%x unitsize=%ld mediasize=%ld"
|
|
" chipsize=%ld interleave=%d window=%lx\n",
|
|
unit, sc->ds.type, sc->ds.unitSize, sc->ds.mediaSize,
|
|
sc->ds.chipSize, sc->ds.interleaving, sc->ds.window);
|
|
|
|
bufq_init(&sc->buf_queue);
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
#if __FreeBSD_version > 400000 /* XXX ? */
|
|
|
|
static int
|
|
flaprobe (device_t dev)
|
|
{
|
|
int unit;
|
|
struct fla_s *sc;
|
|
device_t bus;
|
|
int i;
|
|
|
|
unit = device_get_unit(dev);
|
|
sc = &softc[unit];
|
|
i = flarealprobe(unit);
|
|
if (i)
|
|
return (i);
|
|
|
|
bus = device_get_parent(dev);
|
|
ISA_SET_RESOURCE(bus, dev, SYS_RES_MEMORY, 0,
|
|
sc->ds.window - KERNBASE, 8192);
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
static int
|
|
flaattach (device_t dev)
|
|
{
|
|
int unit, i;
|
|
|
|
unit = device_get_unit(dev);
|
|
i = flarealattach(unit);
|
|
return (i);
|
|
}
|
|
|
|
static device_method_t fla_methods[] = {
|
|
/* Device interface */
|
|
DEVMETHOD(device_probe, flaprobe),
|
|
DEVMETHOD(device_attach, flaattach),
|
|
{0, 0}
|
|
};
|
|
|
|
static driver_t fladriver = {
|
|
"fla",
|
|
fla_methods,
|
|
sizeof(struct fla_s),
|
|
};
|
|
|
|
static devclass_t fla_devclass;
|
|
|
|
DEV_DRIVER_MODULE(fla, isa, fladriver, fla_devclass, fla_cdevsw, 0, 0);
|
|
#endif
|
|
|
|
|
|
#if __FreeBSD_version < 400000 /* XXX ? */
|
|
|
|
static int
|
|
flaprobe (struct isa_device *dvp)
|
|
{
|
|
int unit;
|
|
struct fla_s *sc;
|
|
int i;
|
|
|
|
unit = dvp->id_unit;
|
|
sc = &softc[unit];
|
|
i = flarealprobe(unit);
|
|
if (i)
|
|
return (0);
|
|
|
|
dvp->id_maddr = (caddr_t)sc->ds.window;
|
|
dvp->id_msize = 8192;
|
|
|
|
cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &fla_cdevsw);
|
|
return (-1);
|
|
}
|
|
|
|
|
|
static int
|
|
flaattach (struct isa_device *dvp)
|
|
{
|
|
int unit, i;
|
|
|
|
unit = dvp->id_unit;
|
|
i = flarealattach(unit);
|
|
return (i);
|
|
}
|
|
|
|
struct isa_driver fladriver = {
|
|
flaprobe, flaattach, "fla",
|
|
};
|
|
|
|
#endif
|