From 2b02448defdf5b98a9a3e6df428afedcd5f4c2db Mon Sep 17 00:00:00 2001 From: sos Date: Tue, 6 Mar 2001 21:43:46 +0000 Subject: [PATCH] Split out the ata probes in seperate files for each bus type. --- sys/conf/files | 6 +- sys/dev/ata/ata-all.c | 797 ++--------------------------------------- sys/dev/ata/ata-all.h | 13 +- sys/dev/ata/ata-card.c | 108 ++++++ sys/dev/ata/ata-dma.c | 45 --- sys/dev/ata/ata-isa.c | 102 ++++++ sys/dev/ata/ata-pci.c | 681 +++++++++++++++++++++++++++++++++++ 7 files changed, 927 insertions(+), 825 deletions(-) create mode 100644 sys/dev/ata/ata-card.c create mode 100644 sys/dev/ata/ata-isa.c create mode 100644 sys/dev/ata/ata-pci.c diff --git a/sys/conf/files b/sys/conf/files index 9401ffd9bae8..49c61b0b465a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -244,9 +244,13 @@ dev/ar/if_ar.c optional ar dev/ar/if_ar_pci.c optional ar 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-card.c optional ata card +#dev/ata/ata-card.c optional ata pccard +dev/ata/ata-pci.c optional ata pci +dev/ata/ata-dma.c optional ata pci dev/ata/ata-disk.c optional atadisk dev/ata/ata-raid.c optional atadisk -dev/ata/ata-dma.c optional ata dev/ata/atapi-all.c optional atapicd dev/ata/atapi-all.c optional atapifd dev/ata/atapi-all.c optional atapist 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 #include @@ -47,14 +44,6 @@ #include #include #include -#if NPCI > 0 -#include -#include -#endif -#ifdef DEV_ISA -#include -#include -#endif #ifdef __alpha__ #include #endif @@ -62,20 +51,7 @@ #include #include -/* 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 @@ ata_probe(device_t dev) 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 #include #include -#if NPCI > 0 #include -#endif #include #include #include -#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __alpha__ +#include +#endif +#include +#include +#include +#include + +/* 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);