aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorSøren Schmidt <sos@FreeBSD.org>2001-03-06 21:43:46 +0000
committerSøren Schmidt <sos@FreeBSD.org>2001-03-06 21:43:46 +0000
commit331c488d6923759278c4f7305252eb2217beb90e (patch)
treeac151b0c4ce532310cb197c2b92e6282d205eb1a /sys/dev
parentcf0a305e5b10cc62744c31c9f9245da1fae03401 (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ata/ata-all.c797
-rw-r--r--sys/dev/ata/ata-all.h13
-rw-r--r--sys/dev/ata/ata-card.c108
-rw-r--r--sys/dev/ata/ata-dma.c45
-rw-r--r--sys/dev/ata/ata-isa.c102
-rw-r--r--sys/dev/ata/ata-pci.c681
6 files changed, 922 insertions, 824 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index b95a93b61c65..2206ef8d831a 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -28,10 +28,7 @@
* $FreeBSD$
*/
-#include "card.h"
#include "pci.h"
-#include "opt_global.h"
-#include "opt_isa.h"
#include "opt_ata.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -47,14 +44,6 @@
#include <machine/resource.h>
#include <machine/bus.h>
#include <sys/rman.h>
-#if NPCI > 0
-#include <pci/pcivar.h>
-#include <pci/pcireg.h>
-#endif
-#ifdef DEV_ISA
-#include <isa/isavar.h>
-#include <isa/isareg.h>
-#endif
#ifdef __alpha__
#include <machine/md_var.h>
#endif
@@ -62,20 +51,7 @@
#include <dev/ata/ata-disk.h>
#include <dev/ata/atapi-all.h>
-/* misc defines */
-#define IOMASK 0xfffffffc
-#define ATA_IOADDR_RID 0
-#define ATA_ALTADDR_RID 1
-#define ATA_BMADDR_RID 2
-#define ATA_IRQ_RID 0
-#define ATA_MASTERDEV(dev) ((pci_get_progif(dev) & 0x80) && \
- (pci_get_progif(dev) & 0x05) != 0x05)
-
/* prototypes */
-static int ata_probe(device_t);
-static int ata_attach(device_t);
-static int ata_detach(device_t);
-static int ata_resume(device_t);
static void ata_boot_attach(void);
static void ata_intr(void *);
static int ata_getparam(struct ata_softc *, int, u_int8_t);
@@ -85,716 +61,15 @@ static void bswap(int8_t *, int);
static void btrim(int8_t *, int);
static void bpack(int8_t *, int8_t *, int);
+/* global vars */
+devclass_t ata_devclass;
+
/* local vars */
-static devclass_t ata_devclass;
-static devclass_t ata_pci_devclass;
static struct intr_config_hook *ata_delayed_attach = NULL;
static char ata_conf[256];
static MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer");
-#ifdef DEV_ISA
-static struct isa_pnp_id ata_ids[] = {
- {0x0006d041, "Generic ESDI/IDE/ATA controller"}, /* PNP0600 */
- {0x0106d041, "Plus Hardcard II"}, /* PNP0601 */
- {0x0206d041, "Plus Hardcard IIXL/EZ"}, /* PNP0602 */
- {0x0306d041, "Generic ATA"}, /* PNP0603 */
- {0}
-};
-
-static int
-ata_isa_probe(device_t dev)
-{
- struct ata_softc *scp = device_get_softc(dev);
- struct resource *io;
- int rid;
- u_long tmp;
-
- /* check isapnp ids */
- if (ISA_PNP_PROBE(device_get_parent(dev), dev, ata_ids) == ENXIO)
- return ENXIO;
-
- /* allocate the io port range to get the start address */
- rid = ATA_IOADDR_RID;
- io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
- ATA_IOSIZE, RF_ACTIVE);
- if (!io)
- return ENOMEM;
-
- /* set the altport range */
- if (bus_get_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, &tmp, &tmp)) {
- bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
- rman_get_start(io) + ATA_ALTOFFSET, ATA_ALTIOSIZE);
- }
-
- bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
- scp->channel = 0;
- scp->flags |= ATA_USE_16BIT;
- return ata_probe(dev);
-}
-
-static device_method_t ata_isa_methods[] = {
- /* device interface */
- DEVMETHOD(device_probe, ata_isa_probe),
- DEVMETHOD(device_attach, ata_attach),
- DEVMETHOD(device_resume, ata_resume),
- { 0, 0 }
-};
-
-static driver_t ata_isa_driver = {
- "ata",
- ata_isa_methods,
- sizeof(struct ata_softc),
-};
-
-DRIVER_MODULE(ata, isa, ata_isa_driver, ata_devclass, 0, 0);
-#endif
-
-#if NCARD > 0
-static int
-ata_pccard_probe(device_t dev)
-{
- struct ata_softc *scp = device_get_softc(dev);
- struct resource *io;
- int rid, len, start, end;
- u_long tmp;
-
- /* allocate the io range to get start and length */
- rid = ATA_IOADDR_RID;
- len = bus_get_resource_count(dev, SYS_RES_IOPORT, rid);
- io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
- ATA_IOSIZE, RF_ACTIVE);
- if (!io)
- return ENOMEM;
-
- /* reallocate the io address to only cover the io ports */
- start = rman_get_start(io);
- end = start + ATA_IOSIZE - 1;
- bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
- io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
- start, end, ATA_IOSIZE, RF_ACTIVE);
- bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
-
- /*
- * if we got more than the default ATA_IOSIZE ports, this is likely
- * a pccard system where the altio ports are located at offset 14
- * otherwise its the normal altio offset
- */
- if (bus_get_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, &tmp, &tmp)) {
- if (len > ATA_IOSIZE) {
- bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
- start + ATA_PCCARD_ALTOFFSET, ATA_ALTIOSIZE);
- }
- else {
- bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
- start + ATA_ALTOFFSET, ATA_ALTIOSIZE);
- }
- }
- else
- return ENOMEM;
-
- scp->channel = 0;
- scp->flags |= (ATA_USE_16BIT | ATA_NO_SLAVE);
- return ata_probe(dev);
-}
-
-static device_method_t ata_pccard_methods[] = {
- /* device interface */
- DEVMETHOD(device_probe, ata_pccard_probe),
- DEVMETHOD(device_attach, ata_attach),
- DEVMETHOD(device_detach, ata_detach),
- { 0, 0 }
-};
-
-static driver_t ata_pccard_driver = {
- "ata",
- ata_pccard_methods,
- sizeof(struct ata_softc),
-};
-
-DRIVER_MODULE(ata, pccard, ata_pccard_driver, ata_devclass, 0, 0);
-#endif
-
-#if NPCI > 0
-struct ata_pci_softc {
- struct resource *bmio;
- int bmaddr;
- struct resource *irq;
- int irqcnt;
-};
-
int
-ata_find_dev(device_t dev, u_int32_t type, u_int32_t revid)
-{
- device_t *children, child;
- int nchildren, i;
-
- if (device_get_children(device_get_parent(dev), &children, &nchildren))
- return 0;
-
- for (i = 0; i < nchildren; i++) {
- child = children[i];
-
- /* check that it's on the same silicon and the device we want */
- if (pci_get_slot(dev) == pci_get_slot(child) &&
- pci_get_vendor(child) == (type & 0xffff) &&
- pci_get_device(child) == ((type & 0xffff0000) >> 16) &&
- pci_get_revid(child) >= revid) {
- free(children, M_TEMP);
- return 1;
- }
- }
- free(children, M_TEMP);
- return 0;
-}
-
-static const char *
-ata_pci_match(device_t dev)
-{
- if (pci_get_class(dev) != PCIC_STORAGE)
- return NULL;
-
- switch (pci_get_devid(dev)) {
- /* supported chipsets */
- case 0x12308086:
- return "Intel PIIX ATA controller";
-
- case 0x70108086:
- return "Intel PIIX3 ATA controller";
-
- case 0x71118086:
- case 0x71998086:
- return "Intel PIIX4 ATA33 controller";
-
- case 0x24218086:
- return "Intel ICH0 ATA33 controller";
-
- case 0x24118086:
- return "Intel ICH ATA66 controller";
-
- case 0x244b8086:
- return "Intel ICH2 ATA100 controller";
-
- case 0x522910b9:
- if (pci_get_revid(dev) < 0x20)
- return "AcerLabs Aladdin ATA controller";
- else
- return "AcerLabs Aladdin ATA33 controller";
-
- case 0x05711106:
- if (ata_find_dev(dev, 0x05861106, 0x02))
- return "VIA 82C586 ATA33 controller";
- if (ata_find_dev(dev, 0x05861106, 0))
- return "VIA 82C586 ATA controller";
- if (ata_find_dev(dev, 0x05961106, 0x12))
- return "VIA 82C596 ATA66 controller";
- if (ata_find_dev(dev, 0x05961106, 0))
- return "VIA 82C596 ATA33 controller";
- if (ata_find_dev(dev, 0x06861106, 0x40))
- return "VIA 82C686 ATA100 controller";
- if (ata_find_dev(dev, 0x06861106, 0))
- return "VIA 82C686 ATA66 controller";
- return "VIA Apollo ATA controller";
-
- case 0x55131039:
- return "SiS 5591 ATA33 controller";
-
- case 0x06491095:
- return "CMD 649 ATA100 controller";
-
- case 0x06481095:
- return "CMD 648 ATA66 controller";
-
- case 0x06461095:
- return "CMD 646 ATA controller";
-
- case 0xc6931080:
- if (pci_get_subclass(dev) == PCIS_STORAGE_IDE)
- return "Cypress 82C693 ATA controller";
- break;
-
- case 0x01021078:
- return "Cyrix 5530 ATA33 controller";
-
- case 0x74091022:
- return "AMD 756 ATA66 controller";
-
- case 0x02111166:
- return "ServerWorks ROSB4 ATA33 controller";
-
- case 0x4d33105a:
- return "Promise ATA33 controller";
-
- case 0x4d38105a:
- return "Promise ATA66 controller";
-
- case 0x0d30105a:
- case 0x4d30105a:
- return "Promise ATA100 controller";
-
- case 0x00041103:
- switch (pci_get_revid(dev)) {
- case 0x00:
- case 0x01:
- return "HighPoint HPT366 ATA66 controller";
- case 0x02:
- return "HighPoint HPT368 ATA66 controller";
- case 0x03:
- case 0x04:
- return "HighPoint HPT370 ATA100 controller";
- default:
- return "Unknown revision HighPoint ATA controller";
- }
-
- /* unsupported but known chipsets, generic DMA only */
- case 0x10001042:
- case 0x10011042:
- return "RZ 100? ATA controller !WARNING! buggy chip data loss possible";
-
- case 0x06401095:
- return "CMD 640 ATA controller !WARNING! buggy chip data loss possible";
-
- /* unknown chipsets, try generic DMA if it seems possible */
- default:
- if (pci_get_class(dev) == PCIC_STORAGE &&
- (pci_get_subclass(dev) == PCIS_STORAGE_IDE))
- return "Generic PCI ATA controller";
- }
- return NULL;
-}
-
-static int
-ata_pci_probe(device_t dev)
-{
- const char *desc = ata_pci_match(dev);
-
- if (desc) {
- device_set_desc(dev, desc);
- return 0;
- }
- else
- return ENXIO;
-}
-
-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)))
- return ENOMEM;
- }
- else {
- if (!(child = device_add_child(dev, "ata", 2)))
- return ENOMEM;
- }
- return 0;
-}
-
-static int
-ata_pci_attach(device_t dev)
-{
- struct ata_pci_softc *sc = device_get_softc(dev);
- u_int8_t class, subclass;
- u_int32_t type, cmd;
- int rid;
-
- /* set up vendor-specific stuff */
- type = pci_get_devid(dev);
- class = pci_get_class(dev);
- subclass = pci_get_subclass(dev);
- cmd = pci_read_config(dev, PCIR_COMMAND, 4);
-
- /* is busmastering supported ? */
- if ((cmd & (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN)) ==
- (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN)) {
-
- /* is there a valid port range to connect to ? */
- rid = 0x20;
- sc->bmio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
- 0, ~0, 1, RF_ACTIVE);
- if (!sc->bmio)
- device_printf(dev, "Busmastering DMA not configured\n");
- }
- else
- device_printf(dev, "Busmastering DMA not supported\n");
-
- /* do extra chipset specific setups */
- switch (type) {
- case 0x522910b9: /* Aladdin need to activate the ATAPI FIFO */
- pci_write_config(dev, 0x53,
- (pci_read_config(dev, 0x53, 1) & ~0x01) | 0x02, 1);
- break;
-
- case 0x4d38105a: /* Promise 66 & 100 need their clock changed */
- case 0x4d30105a:
- case 0x0d30105a:
- ATA_OUTB(sc->bmio, 0x11, ATA_INB(sc->bmio, 0x11) | 0x0a);
- /* FALLTHROUGH */
-
- case 0x4d33105a: /* Promise (all) need burst mode to be turned on */
- ATA_OUTB(sc->bmio, 0x1f, ATA_INB(sc->bmio, 0x1f) | 0x01);
- break;
-
- case 0x00041103: /* HighPoint */
- switch (pci_get_revid(dev)) {
- case 0x00:
- case 0x01:
- /* turn off interrupt prediction */
- pci_write_config(dev, 0x51,
- (pci_read_config(dev, 0x51, 1) & ~0x80), 1);
- break;
-
- case 0x02:
- case 0x03:
- case 0x04:
- /* turn off interrupt prediction */
- pci_write_config(dev, 0x51,
- (pci_read_config(dev, 0x51, 1) & ~0x02), 1);
- pci_write_config(dev, 0x55,
- (pci_read_config(dev, 0x55, 1) & ~0x02), 1);
- /* turn on interrupts */
- pci_write_config(dev, 0x5a,
- (pci_read_config(dev, 0x5a, 1) & ~0x10), 1);
-
- }
- break;
-
- case 0x05711106:
- case 0x74091022: /* VIA 82C586, 82C596, 82C686 & AMD 756 default setup */
-
- /* set prefetch, postwrite */
- pci_write_config(dev, 0x41, pci_read_config(dev, 0x41, 1) | 0xf0, 1);
-
- /* set fifo configuration half'n'half */
- pci_write_config(dev, 0x43,
- (pci_read_config(dev, 0x43, 1) & 0x90) | 0x2a, 1);
-
- /* set status register read retry */
- pci_write_config(dev, 0x44, pci_read_config(dev, 0x44, 1) | 0x08, 1);
-
- /* set DMA read & end-of-sector fifo flush */
- pci_write_config(dev, 0x46,
- (pci_read_config(dev, 0x46, 1) & 0x0c) | 0xf0, 1);
-
- /* set sector size */
- pci_write_config(dev, 0x60, DEV_BSIZE, 2);
- pci_write_config(dev, 0x68, DEV_BSIZE, 2);
-
- /* prepare for ATA-66 on the 82C686 and rev 0x12 and newer 82C596's */
- if (ata_find_dev(dev, 0x06861106, 0) ||
- ata_find_dev(dev, 0x05961106, 0x12)) {
- pci_write_config(dev, 0x50,
- pci_read_config(dev, 0x50, 4) | 0x070f070f, 4);
- }
- break;
-
- case 0x10001042: /* RZ 100? known bad, no DMA */
- case 0x10011042:
- case 0x06401095: /* CMD 640 known bad, no DMA */
- sc->bmio = NULL;
- device_printf(dev, "Busmastering DMA disabled\n");
- }
-
- if (sc->bmio) {
- sc->bmaddr = rman_get_start(sc->bmio);
- BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT, rid, sc->bmio);
- sc->bmio = NULL;
- }
-
- /*
- * the Cypress chip is a mess, it contains two ATA functions, but
- * both channels are visible on the first one.
- * simply ignore the second function for now, as the right
- * solution (ignoring the second channel on the first function)
- * doesn't work with the crappy ATA interrupt setup on the alpha.
- */
- if (pci_get_devid(dev) == 0xc6931080 && pci_get_function(dev) > 1)
- return 0;
-
- ata_pci_add_child(dev, 0);
-
- if (ATA_MASTERDEV(dev) || pci_read_config(dev, 0x18, 4) & IOMASK)
- ata_pci_add_child(dev, 1);
-
- return bus_generic_attach(dev);
-}
-
-static int
-ata_pci_print_child(device_t dev, device_t child)
-{
- struct ata_softc *scp = device_get_softc(child);
- int retval = 0;
-
- retval += bus_print_child_header(dev, child);
- retval += printf(": at 0x%lx", rman_get_start(scp->r_io));
-
- if (ATA_MASTERDEV(dev))
- retval += printf(" irq %d", 14 + scp->channel);
-
- retval += bus_print_child_footer(dev, child);
-
- return retval;
-}
-
-static struct resource *
-ata_pci_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_pci_softc *sc = device_get_softc(dev);
- struct resource *res = NULL;
- int channel = ((struct ata_softc *)device_get_softc(child))->channel;
- int myrid;
-
- if (type == SYS_RES_IOPORT) {
- switch (*rid) {
- case ATA_IOADDR_RID:
- if (ATA_MASTERDEV(dev)) {
- myrid = 0;
- start = (channel ? ATA_SECONDARY : ATA_PRIMARY);
- end = start + ATA_IOSIZE - 1;
- count = ATA_IOSIZE;
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
- SYS_RES_IOPORT, &myrid,
- start, end, count, flags);
- }
- else {
- myrid = 0x10 + 8 * channel;
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT, &myrid,
- start, end, count, flags);
- }
- break;
-
- case ATA_ALTADDR_RID:
- if (ATA_MASTERDEV(dev)) {
- myrid = 0;
- start = (channel ? ATA_SECONDARY : ATA_PRIMARY) + ATA_ALTOFFSET;
- end = start + ATA_ALTIOSIZE - 1;
- count = ATA_ALTIOSIZE;
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
- SYS_RES_IOPORT, &myrid,
- start, end, count, flags);
- }
- else {
- myrid = 0x14 + 8 * channel;
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT, &myrid,
- start, end, count, flags);
- if (res) {
- start = rman_get_start(res) + 2;
- end = start + ATA_ALTIOSIZE - 1;
- count = ATA_ALTIOSIZE;
- BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT, myrid, res);
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT, &myrid,
- start, end, count, flags);
- }
- }
- break;
-
- case ATA_BMADDR_RID:
- if (sc->bmaddr) {
- myrid = 0x20;
- start = (channel == 0 ? sc->bmaddr : sc->bmaddr + ATA_BMIOSIZE);
- end = start + ATA_BMIOSIZE - 1;
- count = ATA_BMIOSIZE;
- res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
- SYS_RES_IOPORT, &myrid,
- start, end, count, flags);
- }
- }
- return res;
- }
-
- if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) {
- if (ATA_MASTERDEV(dev)) {
-#ifdef __alpha__
- return alpha_platform_alloc_ide_intr(channel);
-#else
- int irq = (channel == 0 ? 14 : 15);
-
- return BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
- SYS_RES_IRQ, rid,
- irq, irq, 1, flags & ~RF_SHAREABLE);
-#endif
- }
- else {
- /* primary and secondary channels share the same interrupt */
- sc->irqcnt++;
- if (!sc->irq)
- sc->irq = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IRQ, rid, 0, ~0, 1, flags);
- return sc->irq;
- }
- }
- return 0;
-}
-
-static int
-ata_pci_release_resource(device_t dev, device_t child, int type, int rid,
- struct resource *r)
-{
- struct ata_pci_softc *sc = device_get_softc(dev);
- int channel = ((struct ata_softc *)device_get_softc(child))->channel;
- int myrid = 0;
-
- if (type == SYS_RES_IOPORT) {
- switch (rid) {
- case ATA_IOADDR_RID:
- if (ATA_MASTERDEV(dev))
- myrid = 0;
- else
- myrid = 0x10 + 8 * channel;
- break;
-
- case ATA_ALTADDR_RID:
- if (ATA_MASTERDEV(dev))
- myrid = 0;
- else
- myrid = 0x14 + 8 * channel;
- break;
-
- case ATA_BMADDR_RID:
- myrid = 0x20;
- break;
-
- default:
- return ENOENT;
- }
-
- if (ATA_MASTERDEV(dev))
- /* make the parent just pass through the allocation. */
- return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
- SYS_RES_IOPORT, myrid, r);
- else
- /* we are using the parent resource directly. */
- return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
- SYS_RES_IOPORT, myrid, r);
- }
- if (type == SYS_RES_IRQ) {
- if (rid != ATA_IRQ_RID)
- return ENOENT;
-
- if (ATA_MASTERDEV(dev)) {
-#ifdef __alpha__
- return alpha_platform_release_ide_intr(channel, r);
-#else
- return BUS_RELEASE_RESOURCE(device_get_parent(dev),
- child, SYS_RES_IRQ, rid, r);
-#endif
- }
- else {
- if (--sc->irqcnt)
- return 0;
-
- return BUS_RELEASE_RESOURCE(device_get_parent(dev),
- dev, SYS_RES_IRQ, rid, r);
- }
- }
- return EINVAL;
-}
-
-static int
-ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
- int flags, driver_intr_t *intr, void *arg,
- void **cookiep)
-{
- if (ATA_MASTERDEV(dev)) {
-#ifdef __alpha__
- return alpha_platform_setup_ide_intr(child, irq, intr, arg, cookiep);
-#else
- return BUS_SETUP_INTR(device_get_parent(dev), child, irq,
- flags, intr, arg, cookiep);
-#endif
- }
- else
- return BUS_SETUP_INTR(device_get_parent(dev), dev, irq,
- flags, intr, arg, cookiep);
-}
-
-static int
-ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
- void *cookie)
-{
- if (ATA_MASTERDEV(dev)) {
-#ifdef __alpha__
- return alpha_platform_teardown_ide_intr(child, irq, cookie);
-#else
- return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie);
-#endif
- }
- else
- return BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie);
-}
-
-static device_method_t ata_pci_methods[] = {
- /* device interface */
- DEVMETHOD(device_probe, ata_pci_probe),
- DEVMETHOD(device_attach, ata_pci_attach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
- DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
-
- /* bus methods */
- DEVMETHOD(bus_print_child, ata_pci_print_child),
- DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
- DEVMETHOD(bus_release_resource, ata_pci_release_resource),
- DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
- DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
- DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
- DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
- { 0, 0 }
-};
-
-static driver_t ata_pci_driver = {
- "atapci",
- ata_pci_methods,
- sizeof(struct ata_pci_softc),
-};
-
-DRIVER_MODULE(atapci, pci, ata_pci_driver, ata_pci_devclass, 0, 0);
-
-static int
-ata_pcisub_probe(device_t dev)
-{
- struct ata_softc *scp = 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)
- scp->channel = i;
- }
- free(children, M_TEMP);
- scp->chiptype = pci_get_devid(device_get_parent(dev));
- return ata_probe(dev);
-}
-
-static device_method_t ata_pcisub_methods[] = {
- /* device interface */
- DEVMETHOD(device_probe, ata_pcisub_probe),
- DEVMETHOD(device_attach, ata_attach),
- DEVMETHOD(device_detach, ata_detach),
- DEVMETHOD(device_resume, ata_resume),
- { 0, 0 }
-};
-
-static driver_t ata_pcisub_driver = {
- "ata",
- ata_pcisub_methods,
- sizeof(struct ata_softc),
-};
-
-DRIVER_MODULE(ata, atapci, ata_pcisub_driver, ata_devclass, 0, 0);
-#endif
-
-static int
ata_probe(device_t dev)
{
struct ata_softc *scp = device_get_softc(dev);
@@ -871,7 +146,7 @@ failure:
return ENXIO;
}
-static int
+int
ata_attach(device_t dev)
{
struct ata_softc *scp = device_get_softc(dev);
@@ -887,8 +162,8 @@ ata_attach(device_t dev)
ata_printf(scp, -1, "unable to allocate interrupt\n");
return ENXIO;
}
- if ((error = bus_setup_intr(dev, scp->r_irq, INTR_TYPE_BIO|INTR_ENTROPY, ata_intr,
- scp, &scp->ih)))
+ if ((error = bus_setup_intr(dev, scp->r_irq, INTR_TYPE_BIO|INTR_ENTROPY,
+ ata_intr, scp, &scp->ih)))
return error;
/*
@@ -926,7 +201,7 @@ ata_attach(device_t dev)
return 0;
}
-static int
+int
ata_detach(device_t dev)
{
struct ata_softc *scp = device_get_softc(dev);
@@ -934,6 +209,8 @@ ata_detach(device_t dev)
if (!scp || !(scp->flags & ATA_ATTACHED))
return ENXIO;
+ /* make sure device is not busy SOS XXX */
+
/* disable interrupts on devices */
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_4BIT);
@@ -976,7 +253,7 @@ ata_detach(device_t dev)
return 0;
}
-static int
+int
ata_resume(device_t dev)
{
struct ata_softc *scp = device_get_softc(dev);
@@ -1096,48 +373,14 @@ static void
ata_intr(void *data)
{
struct ata_softc *scp = (struct ata_softc *)data;
- u_int8_t dmastat = 0;
/*
- * since we might share the IRQ with another device, and in some
- * cases with our twin channel, we only want to process interrupts
- * that we know this channel generated.
+ * on PCI systems we might share an interrupt line with another
+ * device or our twin ATA channel, so call scp->intr_func to figure
+ * out if it is really an interrupt we should process here
*/
- switch (scp->chiptype) {
-#if NPCI > 0
- case 0x00041103: /* HighPoint HPT366/368/370 */
- if (((dmastat = ata_dmastatus(scp)) &
- (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != ATA_BMSTAT_INTERRUPT)
- return;
- ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT);
- break;
-
- case 0x06481095: /* CMD 648 */
- case 0x06491095: /* CMD 649 */
- if (!(pci_read_config(device_get_parent(scp->dev), 0x71, 1) &
- (scp->channel ? 0x08 : 0x04)))
- return;
- goto out;
-
- case 0x4d33105a: /* Promise Ultra/Fasttrak 33 */
- case 0x4d38105a: /* Promise Ultra/Fasttrak 66 */
- case 0x4d30105a: /* Promise Ultra/Fasttrak 100 */
- case 0x0d30105a: /* Promise OEM ATA100 */
- if (!(ATA_INL(scp->r_bmio, (scp->channel ? 0x14 : 0x1c)) &
- (scp->channel ? 0x00004000 : 0x00000400)))
- return;
- /* FALLTHROUGH */
-out:
-#endif
- default:
- if (scp->flags & ATA_DMA_ACTIVE) {
- if (!((dmastat = ata_dmastatus(scp)) & ATA_BMSTAT_INTERRUPT))
- return;
- ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT,
- dmastat | ATA_BMSTAT_INTERRUPT);
- }
- }
- DELAY(1);
+ if (scp->intr_func && scp->intr_func(scp))
+ return;
/* if drive is busy it didn't interrupt */
if (ATA_INB(scp->r_altio, ATA_ALTSTAT) & ATA_S_BUSY)
@@ -1365,7 +608,7 @@ ata_reset(struct ata_softc *scp, int *mask)
int
ata_reinit(struct ata_softc *scp)
{
- int mask = 0, omask;
+ int mask = 0, odevices;
scp->active = ATA_REINITING;
scp->running = NULL;
@@ -1374,11 +617,11 @@ ata_reinit(struct ata_softc *scp)
if (scp->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE))
mask |= 0x02;
if (mask) {
- omask = mask;
- ata_printf(scp, -1, "resetting devices .. ");
+ odevices = scp->devices;
+ ata_printf(scp, -1, "resetting devices .. ");
ata_reset(scp, &mask);
- if (omask != mask)
- printf(" device dissapeared! %d ", omask & ~mask);
+ if (odevices != scp->devices)
+ printf(" device dissapeared! 0x%02x ", odevices & ~scp->devices);
#ifdef DEV_ATADISK
if (scp->devices & (ATA_ATA_MASTER) && scp->dev_softc[0])
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index 2b87f5a9f163..d90189dd7941 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -119,6 +119,11 @@
#define ATA_DEV(device) ((device == ATA_MASTER) ? 0 : 1)
#define ATA_PARAM(scp, device) (scp->dev_param[ATA_DEV(device)])
+#define ATA_IOADDR_RID 0
+#define ATA_ALTADDR_RID 1
+#define ATA_BMADDR_RID 2
+#define ATA_IRQ_RID 0
+
/* busmaster DMA related defines */
#define ATA_DMA_ENTRIES 256
#define ATA_DMA_EOT 0x80000000
@@ -284,6 +289,7 @@ struct ata_softc {
struct resource *r_bmio; /* bmio addr resource handle */
struct resource *r_irq; /* interrupt of this channel */
void *ih; /* interrupt handle */
+ int (*intr_func)(struct ata_softc *); /* interrupt function */
u_int32_t chiptype; /* pciid of controller chip */
u_int32_t alignment; /* dma engine min alignment */
struct ata_params *dev_param[2]; /* ptr to devices params */
@@ -336,6 +342,11 @@ struct ata_softc {
extern devclass_t ata_devclass;
/* 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_softc *);
void ata_reset(struct ata_softc *, int *);
int ata_reinit(struct ata_softc *);
@@ -350,9 +361,7 @@ int ata_pio2mode(int);
int ata_pmode(struct ata_params *);
int ata_wmode(struct ata_params *);
int ata_umode(struct ata_params *);
-#if NPCI > 0
int ata_find_dev(device_t, u_int32_t, u_int32_t);
-#endif
void *ata_dmaalloc(struct ata_softc *, int);
void ata_dmainit(struct ata_softc *, int, int, int, int);
diff --git a/sys/dev/ata/ata-card.c b/sys/dev/ata/ata-card.c
new file mode 100644
index 000000000000..55d9afb793bf
--- /dev/null
+++ b/sys/dev/ata/ata-card.c
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 1998,1999,2000,2001 Søren Schmidt
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/disk.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/devicestat.h>
+#include <sys/sysctl.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/ata/ata-all.h>
+
+static int
+ata_pccard_probe(device_t dev)
+{
+ struct ata_softc *scp = device_get_softc(dev);
+ struct resource *io;
+ int rid, len, start, end;
+ u_long tmp;
+
+ /* allocate the io range to get start and length */
+ rid = ATA_IOADDR_RID;
+ len = bus_get_resource_count(dev, SYS_RES_IOPORT, rid);
+ io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
+ ATA_IOSIZE, RF_ACTIVE);
+ if (!io)
+ return ENOMEM;
+
+ /* reallocate the io address to only cover the io ports */
+ start = rman_get_start(io);
+ end = start + ATA_IOSIZE - 1;
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
+ io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ start, end, ATA_IOSIZE, RF_ACTIVE);
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
+
+ /*
+ * if we got more than the default ATA_IOSIZE ports, this is likely
+ * a pccard system where the altio ports are located at offset 14
+ * otherwise its the normal altio offset
+ */
+ if (bus_get_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, &tmp, &tmp)) {
+ if (len > ATA_IOSIZE) {
+ bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
+ start + ATA_PCCARD_ALTOFFSET, ATA_ALTIOSIZE);
+ }
+ else {
+ bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
+ start + ATA_ALTOFFSET, ATA_ALTIOSIZE);
+ }
+ }
+ else
+ return ENOMEM;
+
+ scp->channel = 0;
+ scp->flags |= (ATA_USE_16BIT | ATA_NO_SLAVE);
+ return ata_probe(dev);
+}
+
+static device_method_t ata_pccard_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ata_pccard_probe),
+ DEVMETHOD(device_attach, ata_attach),
+ DEVMETHOD(device_detach, ata_detach),
+ { 0, 0 }
+};
+
+static driver_t ata_pccard_driver = {
+ "ata",
+ ata_pccard_methods,
+ sizeof(struct ata_softc),
+};
+
+DRIVER_MODULE(ata, pccard, ata_pccard_driver, ata_devclass, 0, 0);
diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c
index 86ed3e66a124..4832248426e5 100644
--- a/sys/dev/ata/ata-dma.c
+++ b/sys/dev/ata/ata-dma.c
@@ -38,15 +38,11 @@
#include <sys/devicestat.h>
#include <vm/vm.h>
#include <vm/pmap.h>
-#if NPCI > 0
#include <pci/pcivar.h>
-#endif
#include <machine/bus.h>
#include <sys/rman.h>
#include <dev/ata/ata-all.h>
-#if NPCI > 0
-
/* prototypes */
static void cyrix_timing(struct ata_softc *, int, int);
static void promise_timing(struct ata_softc *, int, int);
@@ -1079,44 +1075,3 @@ hpt_timing(struct ata_softc *scp, int devno, int mode)
pci_write_config(parent, 0x40 + (devno << 2), (timing & ~0x80000000),4);
}
}
-
-#else /* NPCI > 0 */
-
-void *
-ata_dmaalloc(struct ata_softc *scp, int device)
-{
- return 0;
-}
-
-void
-ata_dmainit(struct ata_softc *scp, int device,
- int piomode, int wdmamode, int udmamode)
-{
-}
-
-int
-ata_dmasetup(struct ata_softc *scp, int device, struct ata_dmaentry *dmatab,
- caddr_t data, int32_t count)
-{
- return -1;
-}
-
-void
-ata_dmastart(struct ata_softc *scp, int device,
- struct ata_dmaentry *dmatab, int dir)
-{
-}
-
-int
-ata_dmadone(struct ata_softc *scp)
-{
- return -1;
-}
-
-int
-ata_dmastatus(struct ata_softc *scp)
-{
- return -1;
-}
-
-#endif /* NPCI > 0 */
diff --git a/sys/dev/ata/ata-isa.c b/sys/dev/ata/ata-isa.c
new file mode 100644
index 000000000000..e6328eb36c6e
--- /dev/null
+++ b/sys/dev/ata/ata-isa.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 1998,1999,2000,2001 Søren Schmidt
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/disk.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/devicestat.h>
+#include <sys/sysctl.h>
+#include <machine/stdarg.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 struct isa_pnp_id ata_ids[] = {
+ {0x0006d041, "Generic ESDI/IDE/ATA controller"}, /* PNP0600 */
+ {0x0106d041, "Plus Hardcard II"}, /* PNP0601 */
+ {0x0206d041, "Plus Hardcard IIXL/EZ"}, /* PNP0602 */
+ {0x0306d041, "Generic ATA"}, /* PNP0603 */
+ {0}
+};
+
+static int
+ata_isa_probe(device_t dev)
+{
+ struct ata_softc *scp = device_get_softc(dev);
+ struct resource *io;
+ int rid;
+ u_long tmp;
+
+ /* check isapnp ids */
+ if (ISA_PNP_PROBE(device_get_parent(dev), dev, ata_ids) == ENXIO)
+ return ENXIO;
+
+ /* allocate the io port range to get the start address */
+ rid = ATA_IOADDR_RID;
+ io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
+ ATA_IOSIZE, RF_ACTIVE);
+ if (!io)
+ return ENOMEM;
+
+ /* set the altport range */
+ if (bus_get_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, &tmp, &tmp)) {
+ bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
+ rman_get_start(io) + ATA_ALTOFFSET, ATA_ALTIOSIZE);
+ }
+
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
+ scp->channel = 0;
+ scp->flags |= ATA_USE_16BIT;
+ return ata_probe(dev);
+}
+
+static device_method_t ata_isa_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ata_isa_probe),
+ DEVMETHOD(device_attach, ata_attach),
+ DEVMETHOD(device_resume, ata_resume),
+ { 0, 0 }
+};
+
+static driver_t ata_isa_driver = {
+ "ata",
+ ata_isa_methods,
+ sizeof(struct ata_softc),
+};
+
+DRIVER_MODULE(ata, isa, ata_isa_driver, ata_devclass, 0, 0);
diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c
new file mode 100644
index 000000000000..30991f5ae7bd
--- /dev/null
+++ b/sys/dev/ata/ata-pci.c
@@ -0,0 +1,681 @@
+/*-
+ * Copyright (c) 1998,1999,2000,2001 Søren Schmidt
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/disk.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/devicestat.h>
+#include <sys/sysctl.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#ifdef __alpha__
+#include <machine/md_var.h>
+#endif
+#include <sys/rman.h>
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+
+/* misc defines */
+#define IOMASK 0xfffffffc
+#define ATA_MASTERDEV(dev) ((pci_get_progif(dev) & 0x80) && \
+ (pci_get_progif(dev) & 0x05) != 0x05)
+
+struct ata_pci_softc {
+ struct resource *bmio;
+ int bmaddr;
+ struct resource *irq;
+ int irqcnt;
+};
+
+int
+ata_find_dev(device_t dev, u_int32_t type, u_int32_t revid)
+{
+ device_t *children, child;
+ int nchildren, i;
+
+ if (device_get_children(device_get_parent(dev), &children, &nchildren))
+ return 0;
+
+ for (i = 0; i < nchildren; i++) {
+ child = children[i];
+
+ /* check that it's on the same silicon and the device we want */
+ if (pci_get_slot(dev) == pci_get_slot(child) &&
+ pci_get_vendor(child) == (type & 0xffff) &&
+ pci_get_device(child) == ((type & 0xffff0000) >> 16) &&
+ pci_get_revid(child) >= revid) {
+ free(children, M_TEMP);
+ return 1;
+ }
+ }
+ free(children, M_TEMP);
+ return 0;
+}
+
+static const char *
+ata_pci_match(device_t dev)
+{
+ if (pci_get_class(dev) != PCIC_STORAGE)
+ return NULL;
+
+ switch (pci_get_devid(dev)) {
+ /* supported chipsets */
+ case 0x12308086:
+ return "Intel PIIX ATA controller";
+
+ case 0x70108086:
+ return "Intel PIIX3 ATA controller";
+
+ case 0x71118086:
+ case 0x71998086:
+ return "Intel PIIX4 ATA33 controller";
+
+ case 0x24218086:
+ return "Intel ICH0 ATA33 controller";
+
+ case 0x24118086:
+ return "Intel ICH ATA66 controller";
+
+ case 0x244b8086:
+ return "Intel ICH2 ATA100 controller";
+
+ case 0x522910b9:
+ if (pci_get_revid(dev) < 0x20)
+ return "AcerLabs Aladdin ATA controller";
+ else
+ return "AcerLabs Aladdin ATA33 controller";
+
+ case 0x05711106:
+ if (ata_find_dev(dev, 0x05861106, 0x02))
+ return "VIA 82C586 ATA33 controller";
+ if (ata_find_dev(dev, 0x05861106, 0))
+ return "VIA 82C586 ATA controller";
+ if (ata_find_dev(dev, 0x05961106, 0x12))
+ return "VIA 82C596 ATA66 controller";
+ if (ata_find_dev(dev, 0x05961106, 0))
+ return "VIA 82C596 ATA33 controller";
+ if (ata_find_dev(dev, 0x06861106, 0x40))
+ return "VIA 82C686 ATA100 controller";
+ if (ata_find_dev(dev, 0x06861106, 0))
+ return "VIA 82C686 ATA66 controller";
+ return "VIA Apollo ATA controller";
+
+ case 0x55131039:
+ return "SiS 5591 ATA33 controller";
+
+ case 0x06491095:
+ return "CMD 649 ATA100 controller";
+
+ case 0x06481095:
+ return "CMD 648 ATA66 controller";
+
+ case 0x06461095:
+ return "CMD 646 ATA controller";
+
+ case 0xc6931080:
+ if (pci_get_subclass(dev) == PCIS_STORAGE_IDE)
+ return "Cypress 82C693 ATA controller";
+ break;
+
+ case 0x01021078:
+ return "Cyrix 5530 ATA33 controller";
+
+ case 0x74091022:
+ return "AMD 756 ATA66 controller";
+
+ case 0x02111166:
+ return "ServerWorks ROSB4 ATA33 controller";
+
+ case 0x4d33105a:
+ return "Promise ATA33 controller";
+
+ case 0x4d38105a:
+ return "Promise ATA66 controller";
+
+ case 0x0d30105a:
+ case 0x4d30105a:
+ return "Promise ATA100 controller";
+
+ case 0x00041103:
+ switch (pci_get_revid(dev)) {
+ case 0x00:
+ case 0x01:
+ return "HighPoint HPT366 ATA66 controller";
+ case 0x02:
+ return "HighPoint HPT368 ATA66 controller";
+ case 0x03:
+ case 0x04:
+ return "HighPoint HPT370 ATA100 controller";
+ default:
+ return "Unknown revision HighPoint ATA controller";
+ }
+
+ /* unsupported but known chipsets, generic DMA only */
+ case 0x10001042:
+ case 0x10011042:
+ return "RZ 100? ATA controller !WARNING! buggy chip data loss possible";
+
+ case 0x06401095:
+ return "CMD 640 ATA controller !WARNING! buggy chip data loss possible";
+
+ /* unknown chipsets, try generic DMA if it seems possible */
+ default:
+ if (pci_get_class(dev) == PCIC_STORAGE &&
+ (pci_get_subclass(dev) == PCIS_STORAGE_IDE))
+ return "Generic PCI ATA controller";
+ }
+ return NULL;
+}
+
+static int
+ata_pci_probe(device_t dev)
+{
+ const char *desc = ata_pci_match(dev);
+
+ if (desc) {
+ device_set_desc(dev, desc);
+ return 0;
+ }
+ else
+ return ENXIO;
+}
+
+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)))
+ return ENOMEM;
+ }
+ else {
+ if (!(child = device_add_child(dev, "ata", 2)))
+ return ENOMEM;
+ }
+ return 0;
+}
+
+static int
+ata_pci_attach(device_t dev)
+{
+ struct ata_pci_softc *sc = device_get_softc(dev);
+ u_int8_t class, subclass;
+ u_int32_t type, cmd;
+ int rid;
+
+ /* set up vendor-specific stuff */
+ type = pci_get_devid(dev);
+ class = pci_get_class(dev);
+ subclass = pci_get_subclass(dev);
+ cmd = pci_read_config(dev, PCIR_COMMAND, 4);
+
+ /* is busmastering supported ? */
+ if ((cmd & (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN)) ==
+ (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN)) {
+
+ /* is there a valid port range to connect to ? */
+ rid = 0x20;
+ sc->bmio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->bmio)
+ device_printf(dev, "Busmastering DMA not configured\n");
+ }
+ else
+ device_printf(dev, "Busmastering DMA not supported\n");
+
+ /* do extra chipset specific setups */
+ switch (type) {
+ case 0x522910b9: /* Aladdin need to activate the ATAPI FIFO */
+ pci_write_config(dev, 0x53,
+ (pci_read_config(dev, 0x53, 1) & ~0x01) | 0x02, 1);
+ break;
+
+ case 0x4d38105a: /* Promise 66 & 100 need their clock changed */
+ case 0x4d30105a:
+ case 0x0d30105a:
+ ATA_OUTB(sc->bmio, 0x11, ATA_INB(sc->bmio, 0x11) | 0x0a);
+ /* FALLTHROUGH */
+
+ case 0x4d33105a: /* Promise (all) need burst mode to be turned on */
+ ATA_OUTB(sc->bmio, 0x1f, ATA_INB(sc->bmio, 0x1f) | 0x01);
+ break;
+
+ case 0x00041103: /* HighPoint */
+ switch (pci_get_revid(dev)) {
+ case 0x00:
+ case 0x01:
+ /* turn off interrupt prediction */
+ pci_write_config(dev, 0x51,
+ (pci_read_config(dev, 0x51, 1) & ~0x80), 1);
+ break;
+
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ /* turn off interrupt prediction */
+ pci_write_config(dev, 0x51,
+ (pci_read_config(dev, 0x51, 1) & ~0x02), 1);
+ pci_write_config(dev, 0x55,
+ (pci_read_config(dev, 0x55, 1) & ~0x02), 1);
+ /* turn on interrupts */
+ pci_write_config(dev, 0x5a,
+ (pci_read_config(dev, 0x5a, 1) & ~0x10), 1);
+
+ }
+ break;
+
+ case 0x05711106:
+ case 0x74091022: /* VIA 82C586, 82C596, 82C686 & AMD 756 default setup */
+
+ /* set prefetch, postwrite */
+ pci_write_config(dev, 0x41, pci_read_config(dev, 0x41, 1) | 0xf0, 1);
+
+ /* set fifo configuration half'n'half */
+ pci_write_config(dev, 0x43,
+ (pci_read_config(dev, 0x43, 1) & 0x90) | 0x2a, 1);
+
+ /* set status register read retry */
+ pci_write_config(dev, 0x44, pci_read_config(dev, 0x44, 1) | 0x08, 1);
+
+ /* set DMA read & end-of-sector fifo flush */
+ pci_write_config(dev, 0x46,
+ (pci_read_config(dev, 0x46, 1) & 0x0c) | 0xf0, 1);
+
+ /* set sector size */
+ pci_write_config(dev, 0x60, DEV_BSIZE, 2);
+ pci_write_config(dev, 0x68, DEV_BSIZE, 2);
+
+ /* prepare for ATA-66 on the 82C686 and rev 0x12 and newer 82C596's */
+ if (ata_find_dev(dev, 0x06861106, 0) ||
+ ata_find_dev(dev, 0x05961106, 0x12)) {
+ pci_write_config(dev, 0x50,
+ pci_read_config(dev, 0x50, 4) | 0x070f070f, 4);
+ }
+ break;
+
+ case 0x10001042: /* RZ 100? known bad, no DMA */
+ case 0x10011042:
+ case 0x06401095: /* CMD 640 known bad, no DMA */
+ sc->bmio = NULL;
+ device_printf(dev, "Busmastering DMA disabled\n");
+ }
+
+ if (sc->bmio) {
+ sc->bmaddr = rman_get_start(sc->bmio);
+ BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT, rid, sc->bmio);
+ sc->bmio = NULL;
+ }
+
+ /*
+ * the Cypress chip is a mess, it contains two ATA functions, but
+ * both channels are visible on the first one.
+ * simply ignore the second function for now, as the right
+ * solution (ignoring the second channel on the first function)
+ * doesn't work with the crappy ATA interrupt setup on the alpha.
+ */
+ if (pci_get_devid(dev) == 0xc6931080 && pci_get_function(dev) > 1)
+ return 0;
+
+ ata_pci_add_child(dev, 0);
+
+ if (ATA_MASTERDEV(dev) || pci_read_config(dev, 0x18, 4) & IOMASK)
+ ata_pci_add_child(dev, 1);
+
+ return bus_generic_attach(dev);
+}
+
+static int
+ata_pci_intr(struct ata_softc *scp)
+{
+ u_int8_t dmastat;
+
+ /*
+ * since we might share the IRQ with another device, and in some
+ * cases with our twin channel, we only want to process interrupts
+ * that we know this channel generated.
+ */
+ switch (scp->chiptype) {
+ case 0x00041103: /* HighPoint HPT366/368/370 */
+ if (((dmastat = ata_dmastatus(scp)) &
+ (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != ATA_BMSTAT_INTERRUPT)
+ return 1;
+ ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT);
+ DELAY(1);
+ return 0;
+
+ case 0x06481095: /* CMD 648 */
+ case 0x06491095: /* CMD 649 */
+ if (!(pci_read_config(device_get_parent(scp->dev), 0x71, 1) &
+ (scp->channel ? 0x08 : 0x04)))
+ return 1;
+ break;
+
+ case 0x4d33105a: /* Promise Ultra/Fasttrak 33 */
+ case 0x4d38105a: /* Promise Ultra/Fasttrak 66 */
+ case 0x4d30105a: /* Promise Ultra/Fasttrak 100 */
+ case 0x0d30105a: /* Promise OEM ATA100 */
+ if (!(ATA_INL(scp->r_bmio, (scp->channel ? 0x14 : 0x1c)) &
+ (scp->channel ? 0x00004000 : 0x00000400)))
+ return 1;
+ break;
+ }
+
+ if (scp->flags & ATA_DMA_ACTIVE) {
+ if (!((dmastat = ata_dmastatus(scp)) & ATA_BMSTAT_INTERRUPT))
+ return 1;
+ ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT);
+ DELAY(1);
+ }
+ return 0;
+}
+
+static int
+ata_pci_print_child(device_t dev, device_t child)
+{
+ struct ata_softc *scp = device_get_softc(child);
+ int retval = 0;
+
+ retval += bus_print_child_header(dev, child);
+ retval += printf(": at 0x%lx", rman_get_start(scp->r_io));
+
+ if (ATA_MASTERDEV(dev))
+ retval += printf(" irq %d", 14 + scp->channel);
+
+ retval += bus_print_child_footer(dev, child);
+
+ return retval;
+}
+
+static struct resource *
+ata_pci_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_pci_softc *sc = device_get_softc(dev);
+ struct resource *res = NULL;
+ int channel = ((struct ata_softc *)device_get_softc(child))->channel;
+ int myrid;
+
+ if (type == SYS_RES_IOPORT) {
+ switch (*rid) {
+ case ATA_IOADDR_RID:
+ if (ATA_MASTERDEV(dev)) {
+ myrid = 0;
+ start = (channel ? ATA_SECONDARY : ATA_PRIMARY);
+ end = start + ATA_IOSIZE - 1;
+ count = ATA_IOSIZE;
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ SYS_RES_IOPORT, &myrid,
+ start, end, count, flags);
+ }
+ else {
+ myrid = 0x10 + 8 * channel;
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT, &myrid,
+ start, end, count, flags);
+ }
+ break;
+
+ case ATA_ALTADDR_RID:
+ if (ATA_MASTERDEV(dev)) {
+ myrid = 0;
+ start = (channel ? ATA_SECONDARY : ATA_PRIMARY) + ATA_ALTOFFSET;
+ end = start + ATA_ALTIOSIZE - 1;
+ count = ATA_ALTIOSIZE;
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ SYS_RES_IOPORT, &myrid,
+ start, end, count, flags);
+ }
+ else {
+ myrid = 0x14 + 8 * channel;
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT, &myrid,
+ start, end, count, flags);
+ if (res) {
+ start = rman_get_start(res) + 2;
+ end = start + ATA_ALTIOSIZE - 1;
+ count = ATA_ALTIOSIZE;
+ BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT, myrid, res);
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT, &myrid,
+ start, end, count, flags);
+ }
+ }
+ break;
+
+ case ATA_BMADDR_RID:
+ if (sc->bmaddr) {
+ myrid = 0x20;
+ start = (channel == 0 ? sc->bmaddr : sc->bmaddr + ATA_BMIOSIZE);
+ end = start + ATA_BMIOSIZE - 1;
+ count = ATA_BMIOSIZE;
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ SYS_RES_IOPORT, &myrid,
+ start, end, count, flags);
+ }
+ }
+ return res;
+ }
+
+ if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) {
+ if (ATA_MASTERDEV(dev)) {
+#ifdef __alpha__
+ return alpha_platform_alloc_ide_intr(channel);
+#else
+ int irq = (channel == 0 ? 14 : 15);
+
+ return BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ SYS_RES_IRQ, rid,
+ irq, irq, 1, flags & ~RF_SHAREABLE);
+#endif
+ }
+ else {
+ /* primary and secondary channels share the same interrupt */
+ sc->irqcnt++;
+ if (!sc->irq)
+ sc->irq = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IRQ, rid, 0, ~0, 1, flags);
+ return sc->irq;
+ }
+ }
+ return 0;
+}
+
+static int
+ata_pci_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct ata_pci_softc *sc = device_get_softc(dev);
+ int channel = ((struct ata_softc *)device_get_softc(child))->channel;
+ int myrid = 0;
+
+ if (type == SYS_RES_IOPORT) {
+ switch (rid) {
+ case ATA_IOADDR_RID:
+ if (ATA_MASTERDEV(dev))
+ myrid = 0;
+ else
+ myrid = 0x10 + 8 * channel;
+ break;
+
+ case ATA_ALTADDR_RID:
+ if (ATA_MASTERDEV(dev))
+ myrid = 0;
+ else
+ myrid = 0x14 + 8 * channel;
+ break;
+
+ case ATA_BMADDR_RID:
+ myrid = 0x20;
+ break;
+
+ default:
+ return ENOENT;
+ }
+
+ if (ATA_MASTERDEV(dev))
+ /* make the parent just pass through the allocation. */
+ return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
+ SYS_RES_IOPORT, myrid, r);
+ else
+ /* we are using the parent resource directly. */
+ return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
+ SYS_RES_IOPORT, myrid, r);
+ }
+ if (type == SYS_RES_IRQ) {
+ if (rid != ATA_IRQ_RID)
+ return ENOENT;
+
+ if (ATA_MASTERDEV(dev)) {
+#ifdef __alpha__
+ return alpha_platform_release_ide_intr(channel, r);
+#else
+ return BUS_RELEASE_RESOURCE(device_get_parent(dev),
+ child, SYS_RES_IRQ, rid, r);
+#endif
+ }
+ else {
+ if (--sc->irqcnt)
+ return 0;
+
+ return BUS_RELEASE_RESOURCE(device_get_parent(dev),
+ dev, SYS_RES_IRQ, rid, r);
+ }
+ }
+ return EINVAL;
+}
+
+static int
+ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
+ int flags, driver_intr_t *intr, void *arg,
+ void **cookiep)
+{
+ if (ATA_MASTERDEV(dev)) {
+#ifdef __alpha__
+ return alpha_platform_setup_ide_intr(child, irq, intr, arg, cookiep);
+#else
+ return BUS_SETUP_INTR(device_get_parent(dev), child, irq,
+ flags, intr, arg, cookiep);
+#endif
+ }
+ else
+ return BUS_SETUP_INTR(device_get_parent(dev), dev, irq,
+ flags, intr, arg, cookiep);
+}
+
+static int
+ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
+ void *cookie)
+{
+ if (ATA_MASTERDEV(dev)) {
+#ifdef __alpha__
+ return alpha_platform_teardown_ide_intr(child, irq, cookie);
+#else
+ return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie);
+#endif
+ }
+ else
+ return BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie);
+}
+
+static device_method_t ata_pci_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ata_pci_probe),
+ DEVMETHOD(device_attach, ata_pci_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* bus methods */
+ DEVMETHOD(bus_print_child, ata_pci_print_child),
+ DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, ata_pci_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
+ { 0, 0 }
+};
+
+static driver_t ata_pci_driver = {
+ "atapci",
+ ata_pci_methods,
+ sizeof(struct ata_pci_softc),
+};
+
+static devclass_t ata_pci_devclass;
+
+DRIVER_MODULE(atapci, pci, ata_pci_driver, ata_pci_devclass, 0, 0);
+
+static int
+ata_pcisub_probe(device_t dev)
+{
+ struct ata_softc *scp = 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)
+ scp->channel = i;
+ }
+ free(children, M_TEMP);
+ scp->chiptype = pci_get_devid(device_get_parent(dev));
+ scp->intr_func = ata_pci_intr;
+ return ata_probe(dev);
+}
+
+static device_method_t ata_pcisub_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ata_pcisub_probe),
+ DEVMETHOD(device_attach, ata_attach),
+ DEVMETHOD(device_detach, ata_detach),
+ DEVMETHOD(device_resume, ata_resume),
+ { 0, 0 }
+};
+
+static driver_t ata_pcisub_driver = {
+ "ata",
+ ata_pcisub_methods,
+ sizeof(struct ata_softc),
+};
+
+DRIVER_MODULE(ata, atapci, ata_pcisub_driver, ata_devclass, 0, 0);