diff options
author | sos <sos@FreeBSD.org> | 2002-12-03 20:20:44 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2002-12-03 20:20:44 +0000 |
commit | 71edc5e4eb36ba021cec4018ead8d4e7bd6d759d (patch) | |
tree | 905ab8bf0e6cc6504398fed7db55f39319883169 /sys | |
parent | 9a5da33a40507cd3fd2cebf1aa8999a6cdd27862 (diff) | |
download | FreeBSD-src-71edc5e4eb36ba021cec4018ead8d4e7bd6d759d.zip FreeBSD-src-71edc5e4eb36ba021cec4018ead8d4e7bd6d759d.tar.gz |
Add support for the PC98 platform to the ATA driver.
This mostly consists of functionality to serialize accesses to
the two ATA channels (which can also be used to "fix" certain
PCI based controllers).
Add support for Acard controllers.
Enable the ATA driver in PC98 GENERIC, and add device hints.
Update man page with latest support.
The PC98 core team has kindly provided me with a PC98
machine that made this all possible, thanks to all that
contributed to that effort, without that this would
probably newer have been possible..
Approved by: re@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.c | 70 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.h | 28 | ||||
-rw-r--r-- | sys/dev/ata/ata-cbus.c | 263 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.c | 8 | ||||
-rw-r--r-- | sys/dev/ata/ata-dma.c | 142 | ||||
-rw-r--r-- | sys/dev/ata/ata-isa.c | 15 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.c | 106 | ||||
-rw-r--r-- | sys/dev/ata/atapi-fd.c | 4 | ||||
-rw-r--r-- | sys/geom/geom_pc98.c | 4 | ||||
-rw-r--r-- | sys/pc98/conf/GENERIC | 12 | ||||
-rw-r--r-- | sys/pc98/conf/GENERIC.hints | 5 |
12 files changed, 614 insertions, 44 deletions
diff --git a/sys/conf/files b/sys/conf/files index 766f4f5..1b14417 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -290,6 +290,7 @@ dev/an/if_an_pci.c optional an pci dev/asr/asr.c optional asr pci dev/ata/ata-all.c optional ata dev/ata/ata-isa.c optional ata isa +dev/ata/ata-cbus.c optional ata pc98 dev/ata/ata-card.c optional ata card dev/ata/ata-card.c optional ata pccard dev/ata/ata-pci.c optional ata pci diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 17f3dc3..e66a4ac 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -87,10 +87,10 @@ static u_int8_t ata_drawersensor(struct ata_device *, int, u_int8_t, u_int8_t); SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters"); /* global vars */ +struct intr_config_hook *ata_delayed_attach = NULL; devclass_t ata_devclass; /* local vars */ -static struct intr_config_hook *ata_delayed_attach = NULL; static MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer"); /* misc defines */ @@ -134,7 +134,9 @@ ata_probe(device_t dev) (int)rman_get_start(ch->r_altio), (ch->r_bmio) ? (int)rman_get_start(ch->r_bmio) : 0); + ch->lock_func(ch, ATA_LF_LOCK); ata_reset(ch); + ch->lock_func(ch, ATA_LF_UNLOCK); ch->device[MASTER].channel = ch; ch->device[MASTER].unit = ATA_MASTER; @@ -186,6 +188,7 @@ ata_attach(device_t dev) * otherwise attach what the probe has found in ch->devices. */ if (!ata_delayed_attach) { + ch->lock_func(ch, ATA_LF_LOCK); if (ch->devices & ATA_ATA_SLAVE) if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY)) ch->devices &= ~ATA_ATA_SLAVE; @@ -213,6 +216,7 @@ ata_attach(device_t dev) #ifdef DEV_ATAPICAM atapi_cam_attach_bus(ch); #endif + ch->lock_func(ch, ATA_LF_UNLOCK); } return 0; } @@ -228,6 +232,7 @@ ata_detach(device_t dev) return ENXIO; /* make sure channel is not busy */ + ch->lock_func(ch, ATA_LF_LOCK); ATA_SLEEPLOCK_CH(ch, ATA_CONTROL); s = splbio(); @@ -274,13 +279,23 @@ ata_detach(device_t dev) ch->r_bmio = NULL; ch->r_irq = NULL; ATA_UNLOCK_CH(ch); + ch->lock_func(ch, ATA_LF_UNLOCK); return 0; } int ata_resume(device_t dev) { - return ata_reinit(device_get_softc(dev)); + struct ata_channel *ch; + int error; + + if (!dev || !(ch = device_get_softc(dev))) + return ENXIO; + + ch->lock_func(ch, ATA_LF_LOCK); + error = ata_reinit(ch); + ch->lock_func(ch, ATA_LF_UNLOCK); + return error; } static int @@ -313,9 +328,10 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) case ATAREINIT: if (!device || !(ch = device_get_softc(device))) return ENXIO; + ch->lock_func(ch, ATA_LF_LOCK); ATA_SLEEPLOCK_CH(ch, ATA_ACTIVE); - if ((error = ata_reinit(ch))) - ATA_UNLOCK_CH(ch); + error = ata_reinit(ch); + ch->lock_func(ch, ATA_LF_UNLOCK); return error; case ATAGMODE: @@ -339,6 +355,7 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) if (!device || !(ch = device_get_softc(device))) return ENXIO; + ch->lock_func(ch, ATA_LF_LOCK); if ((iocmd->device == MASTER || iocmd->device == -1) && iocmd->u.mode.mode[MASTER] >= 0 && ch->device[MASTER].param) { ata_change_mode(&ch->device[MASTER],iocmd->u.mode.mode[MASTER]); @@ -354,6 +371,7 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) } else iocmd->u.mode.mode[SLAVE] = -1; + ch->lock_func(ch, ATA_LF_UNLOCK); return 0; case ATAGPARM: @@ -386,6 +404,7 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) if (!device || !(ch = device_get_softc(device))) return ENXIO; + ch->lock_func(ch, ATA_LF_LOCK); ATA_SLEEPLOCK_CH(ch, ATA_ACTIVE); if (iocmd->device == SLAVE) @@ -399,6 +418,7 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) id2 = ata_drawersensor(atadev, 0, 0x4f, 0); if (id1 != 0xa3 || id2 != 0x5c) { ATA_UNLOCK_CH(ch); + ch->lock_func(ch, ATA_LF_UNLOCK); return ENXIO; } @@ -419,6 +439,7 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) iocmd->u.enclosure.v12 = ata_drawersensor(atadev, 0, 0x24, 0) * 61; ATA_UNLOCK_CH(ch); + ch->lock_func(ch, ATA_LF_UNLOCK); return 0; } @@ -533,12 +554,6 @@ ata_boot_attach(void) struct ata_channel *ch; int ctlr; - if (ata_delayed_attach) { - config_intrhook_disestablish(ata_delayed_attach); - free(ata_delayed_attach, M_TEMP); - ata_delayed_attach = NULL; - } - /* * run through all ata devices and look for real ATA & ATAPI devices * using the hints we found in the early probe, this avoids some of @@ -547,6 +562,7 @@ ata_boot_attach(void) for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) { if (!(ch = devclass_get_softc(ata_devclass, ctlr))) continue; + ch->lock_func(ch, ATA_LF_LOCK); if (ch->devices & ATA_ATA_SLAVE) if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY)) ch->devices &= ~ATA_ATA_SLAVE; @@ -559,24 +575,26 @@ ata_boot_attach(void) if (ch->devices & ATA_ATAPI_MASTER) if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY)) ch->devices &= ~ATA_ATAPI_MASTER; + ch->lock_func(ch, ATA_LF_UNLOCK); } - #ifdef DEV_ATADISK /* now we know whats there, do the real attach, first the ATA disks */ for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) { if (!(ch = devclass_get_softc(ata_devclass, ctlr))) continue; + ch->lock_func(ch, ATA_LF_LOCK); if (ch->devices & ATA_ATA_MASTER) ad_attach(&ch->device[MASTER]); if (ch->devices & ATA_ATA_SLAVE) ad_attach(&ch->device[SLAVE]); + ch->lock_func(ch, ATA_LF_UNLOCK); } - ata_raid_attach(); #endif /* then the atapi devices */ for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) { if (!(ch = devclass_get_softc(ata_devclass, ctlr))) continue; + ch->lock_func(ch, ATA_LF_LOCK); #if DEV_ATAPIALL if (ch->devices & ATA_ATAPI_MASTER) atapi_attach(&ch->device[MASTER]); @@ -586,7 +604,14 @@ ata_boot_attach(void) #ifdef DEV_ATAPICAM atapi_cam_attach_bus(ch); #endif + ch->lock_func(ch, ATA_LF_UNLOCK); } + if (ata_delayed_attach) { + config_intrhook_disestablish(ata_delayed_attach); + free(ata_delayed_attach, M_TEMP); + ata_delayed_attach = NULL; + } + ata_raid_attach(); } static void @@ -598,7 +623,7 @@ ata_intr(void *data) * device or our twin ATA channel, so call ch->intr_func to figure * out if it is really an interrupt we should process here */ - if (ch->intr_func && ch->intr_func(ch)) + if (!ch->intr_func(ch)) return; /* if drive is busy it didn't interrupt */ @@ -638,14 +663,20 @@ ata_intr(void *data) return; } + if (ch->active & ATA_WAIT_INTR) { + ATA_UNLOCK_CH(ch); + return; + } + if ((ch->flags & ATA_QUEUED) && ATA_INB(ch->r_altio, ATA_ALTSTAT) & ATA_S_SERVICE) { ATA_FORCELOCK_CH(ch, ATA_ACTIVE); if (ata_service(ch) == ATA_OP_CONTINUES) return; } - ATA_UNLOCK_CH(ch); ch->running = NULL; + ATA_UNLOCK_CH(ch); + ch->lock_func(ch, ATA_LF_UNLOCK); ata_start(ch); return; } @@ -661,6 +692,7 @@ ata_start(struct ata_channel *ch) #endif int s; + ch->lock_func(ch, ATA_LF_LOCK); if (!ATA_LOCK_CH(ch, ATA_ACTIVE)) return; @@ -703,6 +735,7 @@ ata_start(struct ata_channel *ch) } #endif ATA_UNLOCK_CH(ch); + ch->lock_func(ch, ATA_LF_UNLOCK); splx(s); } @@ -841,10 +874,13 @@ ata_reinit(struct ata_channel *ch) { int devices, misdev, newdev; - if (!ch->r_io || !ch->r_altio || !ch->r_irq) + ATA_FORCELOCK_CH(ch, ATA_CONTROL); + + if (!ch->r_io || !ch->r_altio || !ch->r_irq) { + ATA_UNLOCK_CH(ch); return ENXIO; + } - ATA_FORCELOCK_CH(ch, ATA_CONTROL); ch->running = NULL; devices = ch->devices; ata_printf(ch, -1, "resetting devices ..\n"); @@ -1263,7 +1299,7 @@ ata_change_mode(struct ata_device *atadev, int mode) ATA_SLEEPLOCK_CH(atadev->channel, ATA_ACTIVE); ata_dmainit(atadev, pmode, wmode, umode); ATA_UNLOCK_CH(atadev->channel); - ata_start(atadev->channel); /* XXX SOS */ + ata_start(atadev->channel); } int diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 8c65250..f8c3039 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -112,6 +112,7 @@ #define ATA_ALTSTAT 0x00 /* alternate status register */ #define ATA_ALTOFFSET 0x206 /* alternate registers offset */ #define ATA_PCCARD_ALTOFFSET 0x0e /* do for PCCARD devices */ +#define ATA_PC98_ALTOFFSET 0x10c /* do for PC98 devices */ #define ATA_A_IDS 0x02 /* disable interrupts */ #define ATA_A_RESET 0x04 /* RESET controller */ #define ATA_A_4BIT 0x08 /* 4 head bits */ @@ -119,14 +120,19 @@ /* misc defines */ #define ATA_PRIMARY 0x1f0 #define ATA_SECONDARY 0x170 +#define ATA_PC98_BANK 0x432 #define ATA_IOSIZE 0x08 #define ATA_ALTIOSIZE 0x01 #define ATA_BMIOSIZE 0x08 +#define ATA_PC98_BANKIOSIZE 0x01 #define ATA_OP_FINISHED 0x00 #define ATA_OP_CONTINUES 0x01 #define ATA_IOADDR_RID 0 #define ATA_ALTADDR_RID 1 #define ATA_BMADDR_RID 2 +#define ATA_PC98_ALTADDR_RID 8 +#define ATA_PC98_BANKADDR_RID 9 + #define ATA_IRQ_RID 0 #define ATA_DEV(device) ((device == ATA_MASTER) ? 0 : 1) @@ -223,7 +229,7 @@ struct ata_channel { u_int8_t status; /* last controller status */ u_int8_t error; /* last controller error */ - int active; /* active processing request */ + int active; /* ATA channel state control */ #define ATA_IDLE 0x0000 #define ATA_IMMEDIATE 0x0001 #define ATA_WAIT_INTR 0x0002 @@ -234,6 +240,10 @@ struct ata_channel { #define ATA_ACTIVE_ATAPI 0x0040 #define ATA_CONTROL 0x0080 + void (*lock_func)(struct ata_channel *, int);/* controller lock function */ +#define ATA_LF_LOCK 0x0001 +#define ATA_LF_UNLOCK 0x0002 + TAILQ_HEAD(, ad_request) ata_queue; /* head of ATA queue */ TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */ void *running; /* currently running request */ @@ -247,13 +257,13 @@ struct ata_channel { /* externs */ extern devclass_t ata_devclass; +extern struct intr_config_hook *ata_delayed_attach; /* public prototypes */ int ata_probe(device_t); int ata_attach(device_t); int ata_detach(device_t); int ata_resume(device_t); - void ata_start(struct ata_channel *); void ata_reset(struct ata_channel *); int ata_reinit(struct ata_channel *); @@ -283,18 +293,16 @@ int ata_dmastatus(struct ata_channel *); int ata_dmadone(struct ata_device *); /* macros for locking a channel */ -#define ATA_LOCK_CH(ch, value)\ - atomic_cmpset_int(&(ch)->active, ATA_IDLE, (value)) +#define ATA_LOCK_CH(ch, value) \ + atomic_cmpset_acq_int(&(ch)->active, ATA_IDLE, (value)) -#define ATA_SLEEPLOCK_CH(ch, value)\ - while (!atomic_cmpset_int(&(ch)->active, ATA_IDLE, (value)))\ +#define ATA_SLEEPLOCK_CH(ch, value) \ + while (!atomic_cmpset_acq_int(&(ch)->active, ATA_IDLE, (value))) \ tsleep((caddr_t)&(ch), PRIBIO, "atalck", 1); -#define ATA_FORCELOCK_CH(ch, value)\ - (ch)->active = value; +#define ATA_FORCELOCK_CH(ch, value) atomic_store_rel_int(&(ch)->active, (value)) -#define ATA_UNLOCK_CH(ch)\ - (ch)->active = ATA_IDLE +#define ATA_UNLOCK_CH(ch) atomic_store_rel_int(&(ch)->active, ATA_IDLE) /* macros to hide busspace uglyness */ #define ATA_INB(res, offset) \ diff --git a/sys/dev/ata/ata-cbus.c b/sys/dev/ata/ata-cbus.c new file mode 100644 index 0000000..f0bc10d --- /dev/null +++ b/sys/dev/ata/ata-cbus.c @@ -0,0 +1,263 @@ +/*- + * Copyright (c) 2002 Søren Schmidt <sos@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_ata.h" +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/malloc.h> +#include <machine/resource.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <isa/isavar.h> +#include <dev/ata/ata-all.h> + +/* local vars */ +static bus_addr_t ata_pc98_ports[] = { + 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe +}; + +struct ata_cbus_controller { + struct resource *io; + struct resource *altio; + struct resource *bankio; + struct resource *irq; + int current_bank; +}; + +static int +ata_cbus_probe(device_t dev) +{ + struct resource *io; + int rid; + u_long tmp; + + /* allocate the ioport range */ + rid = ATA_IOADDR_RID; + io = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, ata_pc98_ports, + ATA_IOSIZE, RF_ACTIVE); + if (!io) + return ENOMEM; + isa_load_resourcev(io, ata_pc98_ports, ATA_IOSIZE); + + /* calculate & set the altport range */ + rid = ATA_PC98_ALTADDR_RID; + if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &tmp, &tmp)) { + bus_set_resource(dev, SYS_RES_IOPORT, rid, + rman_get_start(io)+ATA_PC98_ALTOFFSET, ATA_ALTIOSIZE); + } + + /* calculate & set the bank range */ + rid = ATA_PC98_BANKADDR_RID; + if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &tmp, &tmp)) { + bus_set_resource(dev, SYS_RES_IOPORT, rid, + ATA_PC98_BANK, ATA_PC98_BANKIOSIZE); + } + + bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); + return 0; +} + +static int +ata_cbus_attach(device_t dev) +{ + struct ata_cbus_controller *scp = device_get_softc(dev); + int rid; + + /* allocate resources */ + rid = ATA_IOADDR_RID; + scp->io = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, ata_pc98_ports, + ATA_IOSIZE, RF_ACTIVE); + if (!scp->io) + return ENOMEM; + + isa_load_resourcev(scp->io, ata_pc98_ports, ATA_IOSIZE); + + rid = ATA_PC98_ALTADDR_RID; + scp->altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + rman_get_start(scp->io)+ATA_PC98_ALTOFFSET, + ~0, ATA_ALTIOSIZE, RF_ACTIVE); + if (!scp->altio) + return ENOMEM; + + rid = ATA_PC98_BANKADDR_RID; + scp->bankio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + ATA_PC98_BANK, ~0, + ATA_PC98_BANKIOSIZE, RF_ACTIVE); + if (!scp->bankio) + return ENOMEM; + + rid = 0; + scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); + + scp->current_bank = -1; + if (!device_add_child(dev, "ata", 0)) + return ENOMEM; + if (!device_add_child(dev, "ata", 1)) + return ENOMEM; + + return bus_generic_attach(dev); +} + +static struct resource * +ata_cbus_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct ata_cbus_controller *scp = device_get_softc(dev); + + if (type == SYS_RES_IOPORT) { + switch (*rid) { + case ATA_IOADDR_RID: + return scp->io; + case ATA_ALTADDR_RID: + return scp->altio; + } + } + if (type == SYS_RES_IRQ) { + return scp->irq; + } + return 0; +} + +static int +ata_cbus_setup_intr(device_t dev, device_t child, struct resource *irq, + int flags, driver_intr_t *intr, void *arg, + void **cookiep) +{ + return BUS_SETUP_INTR(device_get_parent(dev), dev, irq, + flags, intr, arg, cookiep); +} + +static int +ata_cbus_print_child(device_t dev, device_t child) +{ + struct ata_channel *ch = device_get_softc(child); + int retval = 0; + + retval += bus_print_child_header(dev, child); + retval += printf(" at bank %d", ch->unit); + retval += bus_print_child_footer(dev, child); + return retval; +} + +static int +ata_cbus_intr(struct ata_channel *ch) +{ + struct ata_cbus_controller *scp = + device_get_softc(device_get_parent(ch->dev)); + + return (ch->unit == scp->current_bank); +} + +static void +ata_cbus_banking(struct ata_channel *ch, int flags) +{ + struct ata_cbus_controller *scp = + device_get_softc(device_get_parent(ch->dev)); + + switch (flags) { + case ATA_LF_LOCK: + if (scp->current_bank == ch->unit) + break; + while (!atomic_cmpset_acq_int(&scp->current_bank, -1, ch->unit)) + tsleep((caddr_t)ch->lock_func, PRIBIO, "atalck", 1); + bus_space_write_1(rman_get_bustag(scp->bankio), + rman_get_bushandle(scp->bankio), 0, ch->unit); + break; + + case ATA_LF_UNLOCK: + if (scp->current_bank == -1 || scp->current_bank != ch->unit) + break; + atomic_store_rel_int(&scp->current_bank, -1); + break; + } + return; +} + +static device_method_t ata_cbus_methods[] = { + /* device_interface */ + DEVMETHOD(device_probe, ata_cbus_probe), + DEVMETHOD(device_attach, ata_cbus_attach), + + /* bus methods */ + DEVMETHOD(bus_alloc_resource, ata_cbus_alloc_resource), + DEVMETHOD(bus_setup_intr, ata_cbus_setup_intr), + DEVMETHOD(bus_print_child, ata_cbus_print_child), + { 0, 0 } +}; + +static driver_t ata_cbus_driver = { + "atacbus", + ata_cbus_methods, + sizeof(struct ata_cbus_controller), +}; + +static devclass_t ata_cbus_devclass; + +DRIVER_MODULE(atacbus, isa, ata_cbus_driver, ata_cbus_devclass, 0, 0); + +static int +ata_cbussub_probe(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + device_t *children; + int count, i; + + /* find channel number on this controller */ + device_get_children(device_get_parent(dev), &children, &count); + for (i = 0; i < count; i++) { + if (children[i] == dev) + ch->unit = i; + } + free(children, M_TEMP); + ch->flags |= ATA_USE_16BIT; + ch->intr_func = ata_cbus_intr; + ch->lock_func = ata_cbus_banking; + return ata_probe(dev); +} + +static device_method_t ata_cbussub_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ata_cbussub_probe), + DEVMETHOD(device_attach, ata_attach), + DEVMETHOD(device_detach, ata_detach), + DEVMETHOD(device_resume, ata_resume), + { 0, 0 } +}; + +static driver_t ata_cbussub_driver = { + "ata", + ata_cbussub_methods, + sizeof(struct ata_channel), +}; + +DRIVER_MODULE(ata, atacbus, ata_cbussub_driver, ata_devclass, 0, 0); diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index f8bae5e..05e4ad9 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -268,6 +268,10 @@ adopen(dev_t dev, int flags, int fmt, struct thread *td) if (adp->flags & AD_F_RAID_SUBDISK) return EBUSY; + + /* hold off access to we are fully attached */ + while (ata_delayed_attach) + tsleep(&ata_delayed_attach, PRIBIO, "adopn", 1); return 0; } @@ -276,10 +280,12 @@ adclose(dev_t dev, int flags, int fmt, struct thread *td) { struct ad_softc *adp = dev->si_drv1; + adp->device->channel->lock_func(adp->device->channel, ATA_LF_LOCK); ATA_SLEEPLOCK_CH(adp->device->channel, ATA_CONTROL); if (ata_command(adp->device, ATA_C_FLUSHCACHE, 0, 0, 0, ATA_WAIT_READY)) ata_prtdev(adp->device, "flushing cache on close failed\n"); ATA_UNLOCK_CH(adp->device->channel); + adp->device->channel->lock_func(adp->device->channel, ATA_LF_UNLOCK); return 0; } @@ -312,7 +318,9 @@ addump(dev_t dev, void *virtual, vm_offset_t physical, off_t offset, size_t leng if (!once) { /* force PIO mode for dumps */ adp->device->mode = ATA_PIO; + adp->device->channel->lock_func(adp->device->channel, ATA_LF_LOCK); ata_reinit(adp->device->channel); + adp->device->channel->lock_func(adp->device->channel, ATA_LF_UNLOCK); once = 1; } diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 030e0ae..607f833 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -1259,6 +1259,148 @@ ata_dmainit(struct ata_device *atadev, int apiomode, int wdmamode, int udmamode) atadev->mode = ATA_PIO0 + apiomode; return; + case 0x00091191: /* Acard ATP865R controller */ + case 0x00081191: /* Acard ATP865 controller */ + if (ATAPI_DEVICE(atadev)) + break; + if (udmamode >= 6) { + error = ata_command(atadev, ATA_C_SETFEATURES, 0, + ATA_UDMA6, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_prtdev(atadev, "%s setting up UDMA6 mode on Acard chip\n", + (error) ? "failed" : "success"); + if (!error) { + u_int16_t reg44 = pci_read_config(parent, 0x44, 2); + + reg44 &= ~(0x000f << (devno << 2)); + reg44 |= (0x0007 << (devno << 2)); + pci_write_config(parent, 0x44, reg44, 2); + pci_write_config(parent, 0x4a, 0xa6, 1); + pci_write_config(parent, 0x40 + devno, 0x031, 1); + ata_dmacreate(atadev, apiomode, ATA_UDMA6); + return; + } + } + if (udmamode >= 5) { + error = ata_command(atadev, ATA_C_SETFEATURES, 0, + ATA_UDMA5, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_prtdev(atadev, "%s setting up UDMA5 mode on Acard chip\n", + (error) ? "failed" : "success"); + if (!error) { + u_int16_t reg44 = pci_read_config(parent, 0x44, 2); + + reg44 &= ~(0x000f << (devno << 2)); + reg44 |= (0x0006 << (devno << 2)); + pci_write_config(parent, 0x44, reg44, 2); + pci_write_config(parent, 0x4a, 0xa6, 1); + pci_write_config(parent, 0x40 + devno, 0x031, 1); + ata_dmacreate(atadev, apiomode, ATA_UDMA5); + return; + } + } + /* FALLTHROUGH */ + + case 0x00071191: /* Acard ATP860R controller */ + case 0x00061191: /* Acard ATP860 controller */ + if (ATAPI_DEVICE(atadev)) + break; + if (udmamode >= 4) { + error = ata_command(atadev, ATA_C_SETFEATURES, 0, + ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_prtdev(atadev, "%s setting up UDMA4 mode on Acard chip\n", + (error) ? "failed" : "success"); + if (!error) { + u_int16_t reg44 = pci_read_config(parent, 0x44, 2); + + reg44 &= ~(0x000f << (devno << 2)); + reg44 |= (0x0005 << (devno << 2)); + pci_write_config(parent, 0x44, reg44, 2); + pci_write_config(parent, 0x4a, 0xa6, 1); + pci_write_config(parent, 0x40 + devno, 0x031, 1); + ata_dmacreate(atadev, apiomode, ATA_UDMA4); + return; + } + } + if (udmamode >= 2) { + error = ata_command(atadev, ATA_C_SETFEATURES, 0, + ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_prtdev(atadev, "%s setting up UDMA2 mode on Acard chip\n", + (error) ? "failed" : "success"); + if (!error) { + u_int16_t reg44 = pci_read_config(parent, 0x44, 2); + + reg44 &= ~(0x000f << (devno << 2)); + reg44 |= (0x0003 << (devno << 2)); + pci_write_config(parent, 0x44, reg44, 2); + pci_write_config(parent, 0x4a, 0xa6, 1); + pci_write_config(parent, 0x40 + devno, 0x031, 1); + ata_dmacreate(atadev, apiomode, ATA_UDMA2); + return; + } + } + if (wdmamode >= 2 && apiomode >= 4) { + error = ata_command(atadev, ATA_C_SETFEATURES, 0, + ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_prtdev(atadev, "%s setting up WDMA2 mode on Acard chip\n", + (error) ? "failed" : "success"); + if (!error) { + u_int16_t reg44 = pci_read_config(parent, 0x44, 2); + + reg44 &= ~(0x000f << (devno << 2)); + pci_write_config(parent, 0x44, reg44, 2); + pci_write_config(parent, 0x4a, 0xa6, 1); + pci_write_config(parent, 0x40 + devno, 0x031, 1); + ata_dmacreate(atadev, apiomode, ATA_WDMA2); + return; + } + } + /* we could set PIO mode timings, but we assume the BIOS did that */ + break; + + case 0x00051191: /* Acard ATP850UF controller */ + if (ATAPI_DEVICE(atadev)) + break; + if (udmamode >= 2) { + error = ata_command(atadev, ATA_C_SETFEATURES, 0, + ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_prtdev(atadev, "%s setting up UDMA2 mode on Acard chip\n", + (error) ? "failed" : "success"); + if (!error) { + u_int8_t reg54 = pci_read_config(parent, 0x54, 1); + + reg54 |= (0x03 << (devno << 1)); + pci_write_config(parent, 0x54, reg54, 1); + pci_write_config(parent, 0x4a, 0xa6, 1); + pci_write_config(parent, 0x40 + (devno << 1), 0x0301, 2); + ata_dmacreate(atadev, apiomode, ATA_UDMA2); + return; + } + } + if (wdmamode >= 2 && apiomode >= 4) { + error = ata_command(atadev, ATA_C_SETFEATURES, 0, + ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_prtdev(atadev, "%s setting up WDMA2 mode on Acard chip\n", + (error) ? "failed" : "success"); + if (!error) { + u_int8_t reg54 = pci_read_config(parent, 0x54, 1); + + reg54 &= ~(0x03 << (devno << 1)); + pci_write_config(parent, 0x54, reg54, 1); + pci_write_config(parent, 0x4a, 0xa6, 1); + pci_write_config(parent, 0x40 + (devno << 1), 0x0301, 2); + ata_dmacreate(atadev, apiomode, ATA_WDMA2); + return; + } + } + /* we could set PIO mode timings, but we assume the BIOS did that */ + break; + case 0x000116ca: /* Cenatek Rocket Drive controller */ if (wdmamode >= 0 && (ATA_INB(atadev->channel->r_bmio, ATA_BMSTAT_PORT) & diff --git a/sys/dev/ata/ata-isa.c b/sys/dev/ata/ata-isa.c index f846caa..1034858 100644 --- a/sys/dev/ata/ata-isa.c +++ b/sys/dev/ata/ata-isa.c @@ -53,6 +53,17 @@ static struct isa_pnp_id ata_ids[] = { }; static int +ata_isa_intrnoop(struct ata_channel *ch) +{ + return 1; + +} +static void +ata_isa_lock(struct ata_channel *ch, int type) +{ +} + +static int ata_isa_probe(device_t dev) { struct ata_channel *ch = device_get_softc(dev); @@ -64,7 +75,7 @@ ata_isa_probe(device_t dev) if (ISA_PNP_PROBE(device_get_parent(dev), dev, ata_ids) == ENXIO) return ENXIO; - /* allocate the io port range to get the start address */ + /* allocate the io port range */ rid = ATA_IOADDR_RID; io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, ATA_IOSIZE, RF_ACTIVE); @@ -80,6 +91,8 @@ ata_isa_probe(device_t dev) bus_release_resource(dev, SYS_RES_IOPORT, rid, io); ch->unit = 0; ch->flags |= ATA_USE_16BIT; + ch->intr_func = ata_isa_intrnoop; + ch->lock_func = ata_isa_lock; return ata_probe(dev); } diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 0d1a037..9ebcd1b 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -52,6 +52,7 @@ struct ata_pci_controller { int bmaddr; struct resource *irq; int irqcnt; + int lock; }; /* misc defines */ @@ -314,10 +315,25 @@ ata_pci_match(device_t dev) case 0x00081103: switch (pci_get_revid(dev)) { case 0x07: + if (pci_get_function(dev) == 0) + return "HighPoint HPT374 ATA133 controller (channel 0+1)"; + if (pci_get_function(dev) == 1) + return "HighPoint HPT374 ATA133 controller (channel 2+3)"; return "HighPoint HPT374 ATA133 controller"; } return NULL; + case 0x00051191: + return "Acard ATP850 ATA-33 controller"; + + case 0x00061191: + case 0x00071191: + return "Acard ATP860 ATA-66 controller"; + + case 0x00081191: + case 0x00091191: + return "Acard ATP865 ATA-133 controller"; + case 0x000116ca: return "Cenatek Rocket Drive controller"; @@ -354,17 +370,14 @@ ata_pci_probe(device_t dev) static int ata_pci_add_child(device_t dev, int unit) { - device_t child; - /* check if this is located at one of the std addresses */ if (ATA_MASTERDEV(dev)) { - if (!(child = device_add_child(dev, "ata", unit))) + if (!device_add_child(dev, "ata", unit)) return ENOMEM; } else { - if (!(child = - device_add_child(dev, "ata", - devclass_find_free_unit(ata_devclass, 2)))) + if (!device_add_child(dev, "ata", + devclass_find_free_unit(ata_devclass, 2))) return ENOMEM; } return 0; @@ -539,6 +552,7 @@ ata_pci_attach(device_t dev) SYS_RES_IOPORT, rid, controller->bmio); controller->bmio = NULL; } + controller->lock = -1; /* * the Cypress chip is a mess, it contains two ATA functions, but @@ -574,16 +588,16 @@ ata_pci_intr(struct ata_channel *ch) case 0x00081103: /* HighPoint HPT374 */ if (((dmastat = ata_dmastatus(ch)) & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != ATA_BMSTAT_INTERRUPT) - return 1; + return 0; ATA_OUTB(ch->r_bmio, ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT); DELAY(1); - return 0; + return 1; case 0x06481095: /* CMD 648 */ case 0x06491095: /* CMD 649 */ if (!(pci_read_config(device_get_parent(ch->dev), 0x71, 1) & (ch->unit ? 0x08 : 0x04))) - return 1; + return 0; break; case 0x4d33105a: /* Promise Ultra/Fasttrak 33 */ @@ -593,7 +607,7 @@ ata_pci_intr(struct ata_channel *ch) case 0x4d30105a: /* Promise Ultra/Fasttrak 100 */ if (!(ATA_INL(ch->r_bmio, (ch->unit ? 0x14 : 0x1c)) & (ch->unit ? 0x00004000 : 0x00000400))) - return 1; + return 0; break; case 0x4d68105a: /* Promise TX2 ATA100 */ @@ -604,17 +618,70 @@ ata_pci_intr(struct ata_channel *ch) case 0x7275105a: /* Promise TX2 ATA133 */ ATA_OUTB(ch->r_bmio, ATA_BMDEVSPEC_0, 0x0b); if (!(ATA_INB(ch->r_bmio, ATA_BMDEVSPEC_1) & 0x20)) - return 1; + return 0; break; + + case 0x00051191: /* Acard ATP850 */ + { + struct ata_pci_controller *scp = + device_get_softc(device_get_parent(ch->dev)); + + if (ch->unit != scp->lock) + return 0; + } + /* FALLTHROUGH */ + + case 0x00061191: /* Acard ATP860 */ + case 0x00071191: /* Acard ATP860R */ + case 0x00081191: /* Acard ATP865 */ + case 0x00091191: /* Acard ATP865R */ + if (ch->flags & ATA_DMA_ACTIVE) { + if (!((dmastat = ata_dmastatus(ch)) & ATA_BMSTAT_INTERRUPT)) + return 0; + ATA_OUTB(ch->r_bmio, ATA_BMSTAT_PORT, dmastat|ATA_BMSTAT_INTERRUPT); + DELAY(1); + ATA_OUTB(ch->r_bmio, ATA_BMCMD_PORT, + ATA_INB(ch->r_bmio, ATA_BMCMD_PORT)&~ATA_BMCMD_START_STOP); + DELAY(1); + } + return 1; } if (ch->flags & ATA_DMA_ACTIVE) { if (!((dmastat = ata_dmastatus(ch)) & ATA_BMSTAT_INTERRUPT)) - return 1; + return 0; ATA_OUTB(ch->r_bmio, ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT); DELAY(1); } - return 0; + return 1; +} + +static void +ata_pci_locknoop(struct ata_channel *ch, int type) +{ +} + +static void +ata_pci_serialize(struct ata_channel *ch, int flags) +{ + struct ata_pci_controller *scp = + device_get_softc(device_get_parent(ch->dev)); + + switch (flags) { + case ATA_LF_LOCK: + if (scp->lock == ch->unit) + break; + while (!atomic_cmpset_acq_int(&scp->lock, -1, ch->unit)) + tsleep((caddr_t)ch->lock_func, PRIBIO, "atalck", 1); + break; + + case ATA_LF_UNLOCK: + if (scp->lock == -1 || scp->lock != ch->unit) + break; + atomic_store_rel_int(&scp->lock, -1); + break; + } + return; } static int @@ -864,8 +931,19 @@ ata_pcisub_probe(device_t dev) ch->unit = i; } free(children, M_TEMP); - ch->chiptype = pci_get_devid(device_get_parent(dev)); + ch->intr_func = ata_pci_intr; + ch->chiptype = pci_get_devid(device_get_parent(dev)); + switch (ch->chiptype) { + case 0x10001042: /* RZ 1000 */ + case 0x10011042: /* RZ 1001 */ + case 0x06401095: /* CMD 640 */ + case 0x00051191: /* Acard ATP850 */ + ch->lock_func = ata_pci_serialize; + break; + default: + ch->lock_func = ata_pci_locknoop; + } return ata_probe(dev); } diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c index e5f887a..2bdbe9d 100644 --- a/sys/dev/ata/atapi-fd.c +++ b/sys/dev/ata/atapi-fd.c @@ -225,6 +225,10 @@ afdopen(dev_t dev, int flags, int fmt, struct thread *td) { struct afd_softc *fdp = dev->si_drv1; + /* hold off access to we are fully attached */ + while (ata_delayed_attach) + tsleep(&ata_delayed_attach, PRIBIO, "afdopn", 1); + atapi_test_ready(fdp->device); if (count_dev(dev) == 1) diff --git a/sys/geom/geom_pc98.c b/sys/geom/geom_pc98.c index 4896346..ebb2ecf 100644 --- a/sys/geom/geom_pc98.c +++ b/sys/geom/geom_pc98.c @@ -190,6 +190,10 @@ g_pc98_taste(struct g_class *mp, struct g_provider *pp, int flags) sectorsize = cp->provider->sectorsize; if (sectorsize < 512) break; + if (cp->provider->mediasize / sectorsize < 17 * 8 * 65536) { + fwsectors = 17; + fwheads = 8; + } gsp->frontstuff = sectorsize * fwsectors; spercyl = (off_t)fwsectors * fwheads * sectorsize; buf = g_read_data(cp, 0, diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC index d822edf..5559e3d 100644 --- a/sys/pc98/conf/GENERIC +++ b/sys/pc98/conf/GENERIC @@ -78,11 +78,19 @@ options COMPAT_OLDISA # Old ISA driver shims # Floppy drives device fdc +# ATA and ATAPI devices +device ata +device atadisk # ATA disk drives +device atapicd # ATAPI CDROM drives +device atapifd # ATAPI floppy drives +device atapist # ATAPI tape drives +options ATA_STATIC_ID # Static device numbering + # IDE controller and disks -device wdc 1 +#device wdc 1 # ATAPI devices on wdc -device wcd 1 #IDE CD-ROM +#device wcd 1 #IDE CD-ROM #device wfd 1 #IDE Floppy (e.g. LS-120) #device wst 1 #IDE Tape (e.g. Travan) diff --git a/sys/pc98/conf/GENERIC.hints b/sys/pc98/conf/GENERIC.hints index b33e8e9..5ccb8f9 100644 --- a/sys/pc98/conf/GENERIC.hints +++ b/sys/pc98/conf/GENERIC.hints @@ -1,4 +1,9 @@ # $FreeBSD$ + +hint.atacbus.0.at="isa" +hint.atacbus.0.port="0x640" +hint.atacbus.0.irq="9" + hint.fdc.0.at="isa" hint.fdc.0.port="0x090" hint.fdc.0.irq="11" |