summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/ata.416
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/ata/ata-all.c70
-rw-r--r--sys/dev/ata/ata-all.h28
-rw-r--r--sys/dev/ata/ata-cbus.c263
-rw-r--r--sys/dev/ata/ata-disk.c8
-rw-r--r--sys/dev/ata/ata-dma.c142
-rw-r--r--sys/dev/ata/ata-isa.c15
-rw-r--r--sys/dev/ata/ata-pci.c106
-rw-r--r--sys/dev/ata/atapi-fd.c4
-rw-r--r--sys/geom/geom_pc98.c4
-rw-r--r--sys/pc98/conf/GENERIC12
-rw-r--r--sys/pc98/conf/GENERIC.hints5
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"
OpenPOWER on IntegriCloud