diff options
-rw-r--r-- | share/man/man4/ata.4 | 16 | ||||
-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 |
13 files changed, 630 insertions, 44 deletions
diff --git a/share/man/man4/ata.4 b/share/man/man4/ata.4 index 912785f..50aad25 100644 --- a/share/man/man4/ata.4 +++ b/share/man/man4/ata.4 @@ -50,6 +50,16 @@ In .Cd hint.ata.1.port="0x170" .Cd hint.ata.1.irq="15" .Pp +For PC98 based ATA/ATAPI support: +.Cd device isa +.Cd device ata +.Pp +In +.Pa /boot/device.hints : +.Cd hint.atacbus.0.at="isa" +.Cd hint.atacbus.0.port="0x640" +.Cd hint.atacbus.0.irq="9" +.Pp For PCI based ATA/ATAPI support: .Cd device pci .Cd device ata @@ -95,6 +105,12 @@ Ultra DMA 100 (UDMA5), 100 MB/sec (depending on model, max stated at boot) Ultra DMA 66 (UDMA4), 66 MB/sec .It AMD 766 Ultra DMA 100 (UDMA5), 100 MB/sec +.It Acard ATP850 +Ultra DMA 33 (UDMA2), 33 MB/sec +.It Acard ATP860 +Ultra DMA 66 (UDMA4), 66 MB/sec +.It Acard ATP865 +Ultra DMA 133 (UDMA6), 133 MB/sec .It CMD 646 DMA 2 (WDMA2), 16 MB/sec .It CMD 648 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" |