1331c488dSSøren Schmidt /*- 2e2bf77c5SSøren Schmidt * Copyright (c) 1998 - 2006 S�ren Schmidt <sos@FreeBSD.org> 3331c488dSSøren Schmidt * All rights reserved. 4331c488dSSøren Schmidt * 5331c488dSSøren Schmidt * Redistribution and use in source and binary forms, with or without 6331c488dSSøren Schmidt * modification, are permitted provided that the following conditions 7331c488dSSøren Schmidt * are met: 8331c488dSSøren Schmidt * 1. Redistributions of source code must retain the above copyright 9331c488dSSøren Schmidt * notice, this list of conditions and the following disclaimer, 10331c488dSSøren Schmidt * without modification, immediately at the beginning of the file. 11331c488dSSøren Schmidt * 2. Redistributions in binary form must reproduce the above copyright 12331c488dSSøren Schmidt * notice, this list of conditions and the following disclaimer in the 13331c488dSSøren Schmidt * documentation and/or other materials provided with the distribution. 14331c488dSSøren Schmidt * 15331c488dSSøren Schmidt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16331c488dSSøren Schmidt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17331c488dSSøren Schmidt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18331c488dSSøren Schmidt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19331c488dSSøren Schmidt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20331c488dSSøren Schmidt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21331c488dSSøren Schmidt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22331c488dSSøren Schmidt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23331c488dSSøren Schmidt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24331c488dSSøren Schmidt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25331c488dSSøren Schmidt */ 26331c488dSSøren Schmidt 27aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 28aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 29aad970f1SDavid E. O'Brien 307800211bSSøren Schmidt #include "opt_ata.h" 31331c488dSSøren Schmidt #include <sys/param.h> 32331c488dSSøren Schmidt #include <sys/systm.h> 33331c488dSSøren Schmidt #include <sys/kernel.h> 34331c488dSSøren Schmidt #include <sys/module.h> 358ca4df32SSøren Schmidt #include <sys/ata.h> 36331c488dSSøren Schmidt #include <sys/bus.h> 37331c488dSSøren Schmidt #include <sys/malloc.h> 38a7a120f6SSøren Schmidt #include <sys/sema.h> 395fdbb0d2SSøren Schmidt #include <sys/taskqueue.h> 405df3ca78SSøren Schmidt #include <vm/uma.h> 41331c488dSSøren Schmidt #include <machine/stdarg.h> 42331c488dSSøren Schmidt #include <machine/resource.h> 43331c488dSSøren Schmidt #include <machine/bus.h> 44331c488dSSøren Schmidt #ifdef __alpha__ 45331c488dSSøren Schmidt #include <machine/md_var.h> 46331c488dSSøren Schmidt #endif 47331c488dSSøren Schmidt #include <sys/rman.h> 484fbd232cSWarner Losh #include <dev/pci/pcivar.h> 494fbd232cSWarner Losh #include <dev/pci/pcireg.h> 50331c488dSSøren Schmidt #include <dev/ata/ata-all.h> 51bb5bdd38SSøren Schmidt #include <dev/ata/ata-pci.h> 528ca4df32SSøren Schmidt #include <ata_if.h> 53331c488dSSøren Schmidt 54bb5bdd38SSøren Schmidt /* local vars */ 555bb84bc8SRobert Watson static MALLOC_DEFINE(M_ATAPCI, "ata_pci", "ATA driver PCI"); 56331c488dSSøren Schmidt 5772c2f499SSøren Schmidt /* misc defines */ 5872c2f499SSøren Schmidt #define IOMASK 0xfffffffc 597af3abd8SSøren Schmidt #define ATA_PROBE_OK -10 6072c2f499SSøren Schmidt 61bb5bdd38SSøren Schmidt /* prototypes */ 620068f98fSSøren Schmidt static void ata_pci_dmainit(device_t); 63331c488dSSøren Schmidt 644ee3fbe8SSøren Schmidt int 654ee3fbe8SSøren Schmidt ata_legacy(device_t dev) 664ee3fbe8SSøren Schmidt { 674ee3fbe8SSøren Schmidt return ((pci_read_config(dev, PCIR_PROGIF, 1)&PCIP_STORAGE_IDE_MASTERDEV) && 684ee3fbe8SSøren Schmidt ((pci_read_config(dev, PCIR_PROGIF, 1) & 694ee3fbe8SSøren Schmidt (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)) != 704ee3fbe8SSøren Schmidt (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))); 714ee3fbe8SSøren Schmidt } 724ee3fbe8SSøren Schmidt 738ca4df32SSøren Schmidt int 74331c488dSSøren Schmidt ata_pci_probe(device_t dev) 75331c488dSSøren Schmidt { 76bb5bdd38SSøren Schmidt if (pci_get_class(dev) != PCIC_STORAGE) 77331c488dSSøren Schmidt return ENXIO; 78331c488dSSøren Schmidt 79bb5bdd38SSøren Schmidt switch (pci_get_vendor(dev)) { 80bb5bdd38SSøren Schmidt case ATA_ACARD_ID: 8145f13b84SSøren Schmidt if (!ata_acard_ident(dev)) 827af3abd8SSøren Schmidt return ATA_PROBE_OK; 8345f13b84SSøren Schmidt break; 84bb5bdd38SSøren Schmidt case ATA_ACER_LABS_ID: 8545f13b84SSøren Schmidt if (!ata_ali_ident(dev)) 867af3abd8SSøren Schmidt return ATA_PROBE_OK; 8745f13b84SSøren Schmidt break; 88bb5bdd38SSøren Schmidt case ATA_AMD_ID: 8945f13b84SSøren Schmidt if (!ata_amd_ident(dev)) 907af3abd8SSøren Schmidt return ATA_PROBE_OK; 9145f13b84SSøren Schmidt break; 927ebce023SSøren Schmidt case ATA_ATI_ID: 937ebce023SSøren Schmidt if (!ata_ati_ident(dev)) 947af3abd8SSøren Schmidt return ATA_PROBE_OK; 957ebce023SSøren Schmidt break; 96bb5bdd38SSøren Schmidt case ATA_CYRIX_ID: 9745f13b84SSøren Schmidt if (!ata_cyrix_ident(dev)) 987af3abd8SSøren Schmidt return ATA_PROBE_OK; 9945f13b84SSøren Schmidt break; 100bb5bdd38SSøren Schmidt case ATA_CYPRESS_ID: 10145f13b84SSøren Schmidt if (!ata_cypress_ident(dev)) 1027af3abd8SSøren Schmidt return ATA_PROBE_OK; 10345f13b84SSøren Schmidt break; 104bb5bdd38SSøren Schmidt case ATA_HIGHPOINT_ID: 10545f13b84SSøren Schmidt if (!ata_highpoint_ident(dev)) 1067af3abd8SSøren Schmidt return ATA_PROBE_OK; 10745f13b84SSøren Schmidt break; 108bb5bdd38SSøren Schmidt case ATA_INTEL_ID: 10945f13b84SSøren Schmidt if (!ata_intel_ident(dev)) 1107af3abd8SSøren Schmidt return ATA_PROBE_OK; 11145f13b84SSøren Schmidt break; 11288bdf804SSøren Schmidt case ATA_ITE_ID: 11388bdf804SSøren Schmidt if (!ata_ite_ident(dev)) 1147af3abd8SSøren Schmidt return ATA_PROBE_OK; 11588bdf804SSøren Schmidt break; 1164b55f0c7SSøren Schmidt case ATA_MARVELL_ID: 1174b55f0c7SSøren Schmidt if (!ata_marvell_ident(dev)) 1187af3abd8SSøren Schmidt return ATA_PROBE_OK; 1194b55f0c7SSøren Schmidt break; 120a5cd71eeSSøren Schmidt case ATA_NATIONAL_ID: 121a5cd71eeSSøren Schmidt if (!ata_national_ident(dev)) 1227af3abd8SSøren Schmidt return ATA_PROBE_OK; 123a5cd71eeSSøren Schmidt break; 124bb5bdd38SSøren Schmidt case ATA_NVIDIA_ID: 12545f13b84SSøren Schmidt if (!ata_nvidia_ident(dev)) 1267af3abd8SSøren Schmidt return ATA_PROBE_OK; 12745f13b84SSøren Schmidt break; 128bb5bdd38SSøren Schmidt case ATA_PROMISE_ID: 12945f13b84SSøren Schmidt if (!ata_promise_ident(dev)) 1307af3abd8SSøren Schmidt return ATA_PROBE_OK; 13145f13b84SSøren Schmidt break; 132bb5bdd38SSøren Schmidt case ATA_SERVERWORKS_ID: 13345f13b84SSøren Schmidt if (!ata_serverworks_ident(dev)) 1347af3abd8SSøren Schmidt return ATA_PROBE_OK; 13545f13b84SSøren Schmidt break; 136bb5bdd38SSøren Schmidt case ATA_SILICON_IMAGE_ID: 13745f13b84SSøren Schmidt if (!ata_sii_ident(dev)) 1387af3abd8SSøren Schmidt return ATA_PROBE_OK; 13945f13b84SSøren Schmidt break; 140bb5bdd38SSøren Schmidt case ATA_SIS_ID: 14145f13b84SSøren Schmidt if (!ata_sis_ident(dev)) 1427af3abd8SSøren Schmidt return ATA_PROBE_OK; 14345f13b84SSøren Schmidt break; 144bb5bdd38SSøren Schmidt case ATA_VIA_ID: 14545f13b84SSøren Schmidt if (!ata_via_ident(dev)) 1467af3abd8SSøren Schmidt return ATA_PROBE_OK; 14745f13b84SSøren Schmidt break; 14888bdf804SSøren Schmidt case ATA_CENATEK_ID: 14988bdf804SSøren Schmidt if (pci_get_devid(dev) == ATA_CENATEK_ROCKET) { 150566cf07aSSøren Schmidt ata_generic_ident(dev); 151bb5bdd38SSøren Schmidt device_set_desc(dev, "Cenatek Rocket Drive controller"); 1527af3abd8SSøren Schmidt return ATA_PROBE_OK; 153331c488dSSøren Schmidt } 15445f13b84SSøren Schmidt break; 15588bdf804SSøren Schmidt case ATA_MICRON_ID: 15688bdf804SSøren Schmidt if (pci_get_devid(dev) == ATA_MICRON_RZ1000 || 15788bdf804SSøren Schmidt pci_get_devid(dev) == ATA_MICRON_RZ1001) { 158566cf07aSSøren Schmidt ata_generic_ident(dev); 159bb5bdd38SSøren Schmidt device_set_desc(dev, 16088bdf804SSøren Schmidt "RZ 100? ATA controller !WARNING! data loss/corruption risk"); 1617af3abd8SSøren Schmidt return ATA_PROBE_OK; 162bb5bdd38SSøren Schmidt } 16345f13b84SSøren Schmidt break; 16445f13b84SSøren Schmidt } 165bb5bdd38SSøren Schmidt 166bb5bdd38SSøren Schmidt /* unknown chipset, try generic DMA if it seems possible */ 16745f13b84SSøren Schmidt if ((pci_get_class(dev) == PCIC_STORAGE) && 1687af3abd8SSøren Schmidt (pci_get_subclass(dev) == PCIS_STORAGE_IDE)) { 1697af3abd8SSøren Schmidt if (!ata_generic_ident(dev)) 1707af3abd8SSøren Schmidt return ATA_PROBE_OK; 1717af3abd8SSøren Schmidt } 172bb5bdd38SSøren Schmidt return ENXIO; 173bb5bdd38SSøren Schmidt } 174331c488dSSøren Schmidt 1758ca4df32SSøren Schmidt int 176331c488dSSøren Schmidt ata_pci_attach(device_t dev) 177331c488dSSøren Schmidt { 178566cf07aSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(dev); 179498e5543SSøren Schmidt u_int32_t cmd; 1801b7cfe44SSøren Schmidt int unit; 181331c488dSSøren Schmidt 182566cf07aSSøren Schmidt /* do chipset specific setups only needed once */ 1836230b63cSSøren Schmidt if (ata_legacy(dev) || pci_read_config(dev, PCIR_BAR(2), 4) & IOMASK) 184566cf07aSSøren Schmidt ctlr->channels = 2; 185566cf07aSSøren Schmidt else 186566cf07aSSøren Schmidt ctlr->channels = 1; 187566cf07aSSøren Schmidt ctlr->allocate = ata_pci_allocate; 188566cf07aSSøren Schmidt ctlr->dmainit = ata_pci_dmainit; 1898ca4df32SSøren Schmidt ctlr->dev = dev; 190566cf07aSSøren Schmidt 191498e5543SSøren Schmidt /* if needed try to enable busmastering */ 192498e5543SSøren Schmidt cmd = pci_read_config(dev, PCIR_COMMAND, 2); 1937800211bSSøren Schmidt if (!(cmd & PCIM_CMD_BUSMASTEREN)) { 1947800211bSSøren Schmidt pci_write_config(dev, PCIR_COMMAND, cmd | PCIM_CMD_BUSMASTEREN, 2); 1957800211bSSøren Schmidt cmd = pci_read_config(dev, PCIR_COMMAND, 2); 1967800211bSSøren Schmidt } 197331c488dSSøren Schmidt 198498e5543SSøren Schmidt /* if busmastering mode "stuck" use it */ 199498e5543SSøren Schmidt if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) { 200498e5543SSøren Schmidt ctlr->r_type1 = SYS_RES_IOPORT; 201498e5543SSøren Schmidt ctlr->r_rid1 = ATA_BMADDR_RID; 2025f96beb9SNate Lawson ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, &ctlr->r_rid1, 2035f96beb9SNate Lawson RF_ACTIVE); 204331c488dSSøren Schmidt } 205331c488dSSøren Schmidt 206f5f55db3SSøren Schmidt if (ctlr->chipinit(dev)) 207f5f55db3SSøren Schmidt return ENXIO; 208c2833977SSøren Schmidt 209566cf07aSSøren Schmidt /* attach all channels on this controller */ 2106230b63cSSøren Schmidt for (unit = 0; unit < ctlr->channels; unit++) { 2116230b63cSSøren Schmidt if (unit == 0 && (pci_get_progif(dev) & 0x81) == 0x80) { 2126230b63cSSøren Schmidt device_add_child(dev, "ata", unit); 2136230b63cSSøren Schmidt continue; 2146230b63cSSøren Schmidt } 2156230b63cSSøren Schmidt if (unit == 1 && (pci_get_progif(dev) & 0x84) == 0x80) { 2166230b63cSSøren Schmidt device_add_child(dev, "ata", unit); 2176230b63cSSøren Schmidt continue; 2186230b63cSSøren Schmidt } 2196230b63cSSøren Schmidt device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 2)); 2206230b63cSSøren Schmidt } 2218ca4df32SSøren Schmidt bus_generic_attach(dev); 2228ca4df32SSøren Schmidt return 0; 223f2972d7eSSøren Schmidt } 224498e5543SSøren Schmidt 2258ca4df32SSøren Schmidt int 226498e5543SSøren Schmidt ata_pci_detach(device_t dev) 227498e5543SSøren Schmidt { 228498e5543SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(dev); 2298ca4df32SSøren Schmidt device_t *children; 2308ca4df32SSøren Schmidt int nchildren, i; 231498e5543SSøren Schmidt 2328ca4df32SSøren Schmidt /* detach & delete all children */ 2338ca4df32SSøren Schmidt if (!device_get_children(dev, &children, &nchildren)) { 2348ca4df32SSøren Schmidt for (i = 0; i < nchildren; i++) 2358ca4df32SSøren Schmidt device_delete_child(dev, children[i]); 2368ca4df32SSøren Schmidt free(children, M_TEMP); 237331c488dSSøren Schmidt } 238331c488dSSøren Schmidt 239498e5543SSøren Schmidt if (ctlr->r_irq) { 240498e5543SSøren Schmidt bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle); 241498e5543SSøren Schmidt bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ctlr->r_irq); 242498e5543SSøren Schmidt } 243498e5543SSøren Schmidt if (ctlr->r_res2) 244498e5543SSøren Schmidt bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); 245498e5543SSøren Schmidt if (ctlr->r_res1) 246498e5543SSøren Schmidt bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1, ctlr->r_res1); 247498e5543SSøren Schmidt 248498e5543SSøren Schmidt return 0; 249498e5543SSøren Schmidt } 250331c488dSSøren Schmidt 2518ca4df32SSøren Schmidt struct resource * 252331c488dSSøren Schmidt ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, 253331c488dSSøren Schmidt u_long start, u_long end, u_long count, u_int flags) 254331c488dSSøren Schmidt { 2556ddce903SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 2566ddce903SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 257bb5bdd38SSøren Schmidt struct resource *res = NULL; 258331c488dSSøren Schmidt int myrid; 259331c488dSSøren Schmidt 260331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 261331c488dSSøren Schmidt switch (*rid) { 262331c488dSSøren Schmidt case ATA_IOADDR_RID: 2634ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 2646ddce903SSøren Schmidt start = (unit ? ATA_SECONDARY : ATA_PRIMARY); 265331c488dSSøren Schmidt count = ATA_IOSIZE; 266f2972d7eSSøren Schmidt end = start + count - 1; 267331c488dSSøren Schmidt } 2686230b63cSSøren Schmidt myrid = PCIR_BAR(0) + (unit << 3); 269331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 270331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 271331c488dSSøren Schmidt start, end, count, flags); 272331c488dSSøren Schmidt break; 273331c488dSSøren Schmidt 2740e1eb682SSøren Schmidt case ATA_CTLADDR_RID: 2754ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 2760e1eb682SSøren Schmidt start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_CTLOFFSET; 2770e1eb682SSøren Schmidt count = ATA_CTLIOSIZE; 278f2972d7eSSøren Schmidt end = start + count - 1; 279331c488dSSøren Schmidt } 2806230b63cSSøren Schmidt myrid = PCIR_BAR(1) + (unit << 3); 281331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 282331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 283331c488dSSøren Schmidt start, end, count, flags); 284331c488dSSøren Schmidt break; 285331c488dSSøren Schmidt } 286331c488dSSøren Schmidt } 287331c488dSSøren Schmidt if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) { 2884ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 289331c488dSSøren Schmidt #ifdef __alpha__ 290bbccd832SSøren Schmidt res = alpha_platform_alloc_ide_intr(unit); 291331c488dSSøren Schmidt #else 2926ddce903SSøren Schmidt int irq = (unit == 0 ? 14 : 15); 293331c488dSSøren Schmidt 294bbccd832SSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 295468fe0fdSSøren Schmidt SYS_RES_IRQ, rid, irq, irq, 1, flags); 296331c488dSSøren Schmidt #endif 297331c488dSSøren Schmidt } 298bbccd832SSøren Schmidt else 299bbccd832SSøren Schmidt res = controller->r_irq; 300331c488dSSøren Schmidt } 301bbccd832SSøren Schmidt return res; 302331c488dSSøren Schmidt } 303331c488dSSøren Schmidt 3048ca4df32SSøren Schmidt int 305331c488dSSøren Schmidt ata_pci_release_resource(device_t dev, device_t child, int type, int rid, 306331c488dSSøren Schmidt struct resource *r) 307331c488dSSøren Schmidt { 3086ddce903SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 309331c488dSSøren Schmidt 310331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 311331c488dSSøren Schmidt switch (rid) { 312331c488dSSøren Schmidt case ATA_IOADDR_RID: 313b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 3146230b63cSSøren Schmidt SYS_RES_IOPORT, 3156230b63cSSøren Schmidt PCIR_BAR(0) + (unit << 3), r); 316331c488dSSøren Schmidt break; 317331c488dSSøren Schmidt 3180e1eb682SSøren Schmidt case ATA_CTLADDR_RID: 319b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 3206230b63cSSøren Schmidt SYS_RES_IOPORT, 3216230b63cSSøren Schmidt PCIR_BAR(1) + (unit << 3), r); 322331c488dSSøren Schmidt break; 323331c488dSSøren Schmidt default: 324331c488dSSøren Schmidt return ENOENT; 325331c488dSSøren Schmidt } 326331c488dSSøren Schmidt } 327331c488dSSøren Schmidt if (type == SYS_RES_IRQ) { 328331c488dSSøren Schmidt if (rid != ATA_IRQ_RID) 329331c488dSSøren Schmidt return ENOENT; 330331c488dSSøren Schmidt 3314ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 332331c488dSSøren Schmidt #ifdef __alpha__ 3336ddce903SSøren Schmidt return alpha_platform_release_ide_intr(unit, r); 334331c488dSSøren Schmidt #else 335b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 336b5a5e99dSSøren Schmidt SYS_RES_IRQ, rid, r); 337331c488dSSøren Schmidt #endif 338331c488dSSøren Schmidt } 339bb5bdd38SSøren Schmidt else 340331c488dSSøren Schmidt return 0; 341331c488dSSøren Schmidt } 342331c488dSSøren Schmidt return EINVAL; 343331c488dSSøren Schmidt } 344331c488dSSøren Schmidt 3458ca4df32SSøren Schmidt int 346331c488dSSøren Schmidt ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, 347bb5bdd38SSøren Schmidt int flags, driver_intr_t *function, void *argument, 348331c488dSSøren Schmidt void **cookiep) 349331c488dSSøren Schmidt { 3504ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 351331c488dSSøren Schmidt #ifdef __alpha__ 352bb5bdd38SSøren Schmidt return alpha_platform_setup_ide_intr(child, irq, function, argument, 353bb5bdd38SSøren Schmidt cookiep); 354331c488dSSøren Schmidt #else 355331c488dSSøren Schmidt return BUS_SETUP_INTR(device_get_parent(dev), child, irq, 356bb5bdd38SSøren Schmidt flags, function, argument, cookiep); 357331c488dSSøren Schmidt #endif 358331c488dSSøren Schmidt } 359bb5bdd38SSøren Schmidt else { 360bb5bdd38SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 361bb5bdd38SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 362bb5bdd38SSøren Schmidt 363bb5bdd38SSøren Schmidt controller->interrupt[unit].function = function; 364bb5bdd38SSøren Schmidt controller->interrupt[unit].argument = argument; 365bb5bdd38SSøren Schmidt *cookiep = controller; 366bb5bdd38SSøren Schmidt return 0; 367bb5bdd38SSøren Schmidt } 368331c488dSSøren Schmidt } 369331c488dSSøren Schmidt 3708ca4df32SSøren Schmidt int 371331c488dSSøren Schmidt ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, 372331c488dSSøren Schmidt void *cookie) 373331c488dSSøren Schmidt { 3744ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 375331c488dSSøren Schmidt #ifdef __alpha__ 376331c488dSSøren Schmidt return alpha_platform_teardown_ide_intr(child, irq, cookie); 377331c488dSSøren Schmidt #else 378331c488dSSøren Schmidt return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie); 379331c488dSSøren Schmidt #endif 380331c488dSSøren Schmidt } 3812e6c2a10SSøren Schmidt else { 3822e6c2a10SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 3832e6c2a10SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 3842e6c2a10SSøren Schmidt 3852e6c2a10SSøren Schmidt controller->interrupt[unit].function = NULL; 3862e6c2a10SSøren Schmidt controller->interrupt[unit].argument = NULL; 387bb5bdd38SSøren Schmidt return 0; 388331c488dSSøren Schmidt } 3892e6c2a10SSøren Schmidt } 390331c488dSSøren Schmidt 391b0a7e6a5SSøren Schmidt int 392bbccd832SSøren Schmidt ata_pci_allocate(device_t dev) 393566cf07aSSøren Schmidt { 394566cf07aSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 395bbccd832SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 3960e1eb682SSøren Schmidt struct resource *io = NULL, *ctlio = NULL; 397566cf07aSSøren Schmidt int i, rid; 398566cf07aSSøren Schmidt 399566cf07aSSøren Schmidt rid = ATA_IOADDR_RID; 400ecd6c15dSSøren Schmidt if (!(io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE))) 401566cf07aSSøren Schmidt return ENXIO; 402566cf07aSSøren Schmidt 4030e1eb682SSøren Schmidt rid = ATA_CTLADDR_RID; 404ecd6c15dSSøren Schmidt if (!(ctlio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,RF_ACTIVE))){ 405566cf07aSSøren Schmidt bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); 406566cf07aSSøren Schmidt return ENXIO; 407566cf07aSSøren Schmidt } 408566cf07aSSøren Schmidt 4090e1eb682SSøren Schmidt for (i = ATA_DATA; i <= ATA_COMMAND; i ++) { 410566cf07aSSøren Schmidt ch->r_io[i].res = io; 411566cf07aSSøren Schmidt ch->r_io[i].offset = i; 412566cf07aSSøren Schmidt } 4130e1eb682SSøren Schmidt ch->r_io[ATA_CONTROL].res = ctlio; 4140e1eb682SSøren Schmidt ch->r_io[ATA_CONTROL].offset = ata_legacy(device_get_parent(dev)) ? 0 : 2; 4151b39bd24SSøren Schmidt ch->r_io[ATA_IDX_ADDR].res = io; 4160068f98fSSøren Schmidt ata_default_registers(dev); 417498e5543SSøren Schmidt if (ctlr->r_res1) { 418566cf07aSSøren Schmidt for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) { 419498e5543SSøren Schmidt ch->r_io[i].res = ctlr->r_res1; 420566cf07aSSøren Schmidt ch->r_io[i].offset = (i - ATA_BMCMD_PORT) + (ch->unit*ATA_BMIOSIZE); 421566cf07aSSøren Schmidt } 422566cf07aSSøren Schmidt } 423f2972d7eSSøren Schmidt 424f5f55db3SSøren Schmidt ata_pci_hw(dev); 425566cf07aSSøren Schmidt return 0; 426566cf07aSSøren Schmidt } 427566cf07aSSøren Schmidt 428f5f55db3SSøren Schmidt void 429f5f55db3SSøren Schmidt ata_pci_hw(device_t dev) 430f5f55db3SSøren Schmidt { 431f5f55db3SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 432f5f55db3SSøren Schmidt 433f5f55db3SSøren Schmidt ata_generic_hw(dev); 434f5f55db3SSøren Schmidt ch->hw.status = ata_pci_status; 435f5f55db3SSøren Schmidt } 436f5f55db3SSøren Schmidt 437f5f55db3SSøren Schmidt int 438f5f55db3SSøren Schmidt ata_pci_status(device_t dev) 439f5f55db3SSøren Schmidt { 440f5f55db3SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 441f5f55db3SSøren Schmidt 442f5f55db3SSøren Schmidt if (ch->dma && ((ch->flags & ATA_ALWAYS_DMASTAT) || 443f5f55db3SSøren Schmidt (ch->dma->flags & ATA_DMA_ACTIVE))) { 444f5f55db3SSøren Schmidt int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 445f5f55db3SSøren Schmidt 446f5f55db3SSøren Schmidt if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != 447f5f55db3SSøren Schmidt ATA_BMSTAT_INTERRUPT) 448f5f55db3SSøren Schmidt return 0; 449f5f55db3SSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); 450f5f55db3SSøren Schmidt DELAY(1); 451f5f55db3SSøren Schmidt } 452f5f55db3SSøren Schmidt if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { 453f5f55db3SSøren Schmidt DELAY(100); 454f5f55db3SSøren Schmidt if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) 455f5f55db3SSøren Schmidt return 0; 456f5f55db3SSøren Schmidt } 457f5f55db3SSøren Schmidt return 1; 458f5f55db3SSøren Schmidt } 459f5f55db3SSøren Schmidt 460566cf07aSSøren Schmidt static int 4610068f98fSSøren Schmidt ata_pci_dmastart(device_t dev) 462566cf07aSSøren Schmidt { 463eeda55ceSSøren Schmidt struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 4640068f98fSSøren Schmidt 465566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) | 466566cf07aSSøren Schmidt (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); 4678ca4df32SSøren Schmidt ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->sg_bus); 468c5b2c44cSSøren Schmidt ch->dma->flags |= ATA_DMA_ACTIVE; 469566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 47045bf968aSSøren Schmidt (ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_WRITE_READ) | 47180344be5SSøren Schmidt ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | 47280344be5SSøren Schmidt ATA_BMCMD_START_STOP); 473566cf07aSSøren Schmidt return 0; 474566cf07aSSøren Schmidt } 475566cf07aSSøren Schmidt 476566cf07aSSøren Schmidt static int 4770068f98fSSøren Schmidt ata_pci_dmastop(device_t dev) 478566cf07aSSøren Schmidt { 479eeda55ceSSøren Schmidt struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 480566cf07aSSøren Schmidt int error; 481566cf07aSSøren Schmidt 482566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 483566cf07aSSøren Schmidt ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 4847e6d7588SSøren Schmidt ch->dma->flags &= ~ATA_DMA_ACTIVE; 485c5b2c44cSSøren Schmidt error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 486566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); 4875fdbb0d2SSøren Schmidt return error; 488566cf07aSSøren Schmidt } 489566cf07aSSøren Schmidt 4906419d0b0SSøren Schmidt static void 491eeda55ceSSøren Schmidt ata_pci_dmareset(device_t dev) 492eeda55ceSSøren Schmidt { 493eeda55ceSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 494eeda55ceSSøren Schmidt 495eeda55ceSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 496eeda55ceSSøren Schmidt ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 497eeda55ceSSøren Schmidt ch->dma->flags &= ~ATA_DMA_ACTIVE; 498eeda55ceSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); 499eeda55ceSSøren Schmidt ch->dma->unload(dev); 500eeda55ceSSøren Schmidt } 501eeda55ceSSøren Schmidt 502eeda55ceSSøren Schmidt static void 5030068f98fSSøren Schmidt ata_pci_dmainit(device_t dev) 504566cf07aSSøren Schmidt { 5050068f98fSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 5060068f98fSSøren Schmidt 5070068f98fSSøren Schmidt ata_dmainit(dev); 5086419d0b0SSøren Schmidt if (ch->dma) { 509566cf07aSSøren Schmidt ch->dma->start = ata_pci_dmastart; 510566cf07aSSøren Schmidt ch->dma->stop = ata_pci_dmastop; 511eeda55ceSSøren Schmidt ch->dma->reset = ata_pci_dmareset; 5126419d0b0SSøren Schmidt } 513566cf07aSSøren Schmidt } 514566cf07aSSøren Schmidt 515331c488dSSøren Schmidt static device_method_t ata_pci_methods[] = { 516331c488dSSøren Schmidt /* device interface */ 517331c488dSSøren Schmidt DEVMETHOD(device_probe, ata_pci_probe), 518331c488dSSøren Schmidt DEVMETHOD(device_attach, ata_pci_attach), 519498e5543SSøren Schmidt DEVMETHOD(device_detach, ata_pci_detach), 520331c488dSSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 521331c488dSSøren Schmidt DEVMETHOD(device_suspend, bus_generic_suspend), 522331c488dSSøren Schmidt DEVMETHOD(device_resume, bus_generic_resume), 523331c488dSSøren Schmidt 524331c488dSSøren Schmidt /* bus methods */ 525331c488dSSøren Schmidt DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), 526331c488dSSøren Schmidt DEVMETHOD(bus_release_resource, ata_pci_release_resource), 527331c488dSSøren Schmidt DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 528331c488dSSøren Schmidt DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 529331c488dSSøren Schmidt DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), 530331c488dSSøren Schmidt DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), 5318ca4df32SSøren Schmidt 532331c488dSSøren Schmidt { 0, 0 } 533331c488dSSøren Schmidt }; 534331c488dSSøren Schmidt 5358ca4df32SSøren Schmidt devclass_t atapci_devclass; 5368ca4df32SSøren Schmidt 537331c488dSSøren Schmidt static driver_t ata_pci_driver = { 538331c488dSSøren Schmidt "atapci", 539331c488dSSøren Schmidt ata_pci_methods, 5406ddce903SSøren Schmidt sizeof(struct ata_pci_controller), 541331c488dSSøren Schmidt }; 542331c488dSSøren Schmidt 5438ca4df32SSøren Schmidt DRIVER_MODULE(atapci, pci, ata_pci_driver, atapci_devclass, 0, 0); 5448ca4df32SSøren Schmidt MODULE_VERSION(atapci, 1); 5458ca4df32SSøren Schmidt MODULE_DEPEND(atapci, ata, 1, 1, 1); 546331c488dSSøren Schmidt 547331c488dSSøren Schmidt static int 5485a5b148dSSøren Schmidt ata_pcichannel_probe(device_t dev) 549331c488dSSøren Schmidt { 5506ddce903SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 551331c488dSSøren Schmidt device_t *children; 552d53fc3e4SSøren Schmidt int count, i; 5538ca4df32SSøren Schmidt char buffer[32]; 554331c488dSSøren Schmidt 555498e5543SSøren Schmidt /* take care of green memory */ 556498e5543SSøren Schmidt bzero(ch, sizeof(struct ata_channel)); 557498e5543SSøren Schmidt 558331c488dSSøren Schmidt /* find channel number on this controller */ 559331c488dSSøren Schmidt device_get_children(device_get_parent(dev), &children, &count); 560331c488dSSøren Schmidt for (i = 0; i < count; i++) { 561331c488dSSøren Schmidt if (children[i] == dev) 5626ddce903SSøren Schmidt ch->unit = i; 563331c488dSSøren Schmidt } 564331c488dSSøren Schmidt free(children, M_TEMP); 5658ba4488cSSøren Schmidt 5668ca4df32SSøren Schmidt sprintf(buffer, "ATA channel %d", ch->unit); 5678ca4df32SSøren Schmidt device_set_desc_copy(dev, buffer); 5688ca4df32SSøren Schmidt 569d53fc3e4SSøren Schmidt return ata_probe(dev); 570d53fc3e4SSøren Schmidt } 571d53fc3e4SSøren Schmidt 572d53fc3e4SSøren Schmidt static int 5735a5b148dSSøren Schmidt ata_pcichannel_attach(device_t dev) 574d53fc3e4SSøren Schmidt { 575d53fc3e4SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 576d53fc3e4SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 577d53fc3e4SSøren Schmidt int error; 578d53fc3e4SSøren Schmidt 579a3ebeaa8SSøren Schmidt if (ctlr->dmainit) 5800068f98fSSøren Schmidt ctlr->dmainit(dev); 581d53fc3e4SSøren Schmidt if (ch->dma) 5820068f98fSSøren Schmidt ch->dma->alloc(dev); 583d53fc3e4SSøren Schmidt 584bbccd832SSøren Schmidt if ((error = ctlr->allocate(dev))) 585ca5d21e9SSøren Schmidt return error; 586ca5d21e9SSøren Schmidt 587d53fc3e4SSøren Schmidt return ata_attach(dev); 588331c488dSSøren Schmidt } 589331c488dSSøren Schmidt 590d53fc3e4SSøren Schmidt static int 5915a5b148dSSøren Schmidt ata_pcichannel_detach(device_t dev) 592d53fc3e4SSøren Schmidt { 593d53fc3e4SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 594d53fc3e4SSøren Schmidt int error; 595d53fc3e4SSøren Schmidt 596d53fc3e4SSøren Schmidt if ((error = ata_detach(dev))) 597d53fc3e4SSøren Schmidt return error; 598d53fc3e4SSøren Schmidt 599d53fc3e4SSøren Schmidt if (ch->dma) 6000068f98fSSøren Schmidt ch->dma->free(dev); 601d53fc3e4SSøren Schmidt 602265da99cSSøren Schmidt /* XXX SOS free resources for io and ctlio ?? */ 603bbccd832SSøren Schmidt 604d53fc3e4SSøren Schmidt return 0; 605d53fc3e4SSøren Schmidt } 606d53fc3e4SSøren Schmidt 6075a5b148dSSøren Schmidt static int 6085a5b148dSSøren Schmidt ata_pcichannel_locking(device_t dev, int mode) 6095a5b148dSSøren Schmidt { 6105a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 6115a5b148dSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 6125a5b148dSSøren Schmidt 6135a5b148dSSøren Schmidt if (ctlr->locking) 6140068f98fSSøren Schmidt return ctlr->locking(dev, mode); 6155a5b148dSSøren Schmidt else 6165a5b148dSSøren Schmidt return ch->unit; 6175a5b148dSSøren Schmidt } 6185a5b148dSSøren Schmidt 6195a5b148dSSøren Schmidt static void 6205a5b148dSSøren Schmidt ata_pcichannel_reset(device_t dev) 6215a5b148dSSøren Schmidt { 6225a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 6235a5b148dSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 6245a5b148dSSøren Schmidt 625eeda55ceSSøren Schmidt /* if DMA engine present reset it */ 626b0a7e6a5SSøren Schmidt if (ch->dma) { 627eeda55ceSSøren Schmidt if (ch->dma->reset) 628eeda55ceSSøren Schmidt ch->dma->reset(dev); 6290068f98fSSøren Schmidt ch->dma->unload(dev); 630b0a7e6a5SSøren Schmidt } 631b0a7e6a5SSøren Schmidt 632b0a7e6a5SSøren Schmidt /* reset the controller HW */ 6335a5b148dSSøren Schmidt if (ctlr->reset) 6340068f98fSSøren Schmidt ctlr->reset(dev); 6358dad6b7bSSøren Schmidt else 6360068f98fSSøren Schmidt ata_generic_reset(dev); 6375a5b148dSSøren Schmidt } 6385a5b148dSSøren Schmidt 6395a5b148dSSøren Schmidt static void 6405a5b148dSSøren Schmidt ata_pcichannel_setmode(device_t parent, device_t dev) 6415a5b148dSSøren Schmidt { 6425a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); 6435a5b148dSSøren Schmidt struct ata_device *atadev = device_get_softc(dev); 6445a5b148dSSøren Schmidt int mode = atadev->mode; 6455a5b148dSSøren Schmidt 6460068f98fSSøren Schmidt ctlr->setmode(dev, ATA_PIO_MAX); 6475a5b148dSSøren Schmidt if (mode >= ATA_DMA) 6480068f98fSSøren Schmidt ctlr->setmode(dev, mode); 6495a5b148dSSøren Schmidt } 6505a5b148dSSøren Schmidt 6515a5b148dSSøren Schmidt static device_method_t ata_pcichannel_methods[] = { 652331c488dSSøren Schmidt /* device interface */ 6535a5b148dSSøren Schmidt DEVMETHOD(device_probe, ata_pcichannel_probe), 6545a5b148dSSøren Schmidt DEVMETHOD(device_attach, ata_pcichannel_attach), 6555a5b148dSSøren Schmidt DEVMETHOD(device_detach, ata_pcichannel_detach), 6568ca4df32SSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 657186ba2b7SSøren Schmidt DEVMETHOD(device_suspend, ata_suspend), 658186ba2b7SSøren Schmidt DEVMETHOD(device_resume, ata_resume), 6595a5b148dSSøren Schmidt 6605a5b148dSSøren Schmidt /* ATA methods */ 6615a5b148dSSøren Schmidt DEVMETHOD(ata_setmode, ata_pcichannel_setmode), 6625a5b148dSSøren Schmidt DEVMETHOD(ata_locking, ata_pcichannel_locking), 6635a5b148dSSøren Schmidt DEVMETHOD(ata_reset, ata_pcichannel_reset), 6645a5b148dSSøren Schmidt 665331c488dSSøren Schmidt { 0, 0 } 666331c488dSSøren Schmidt }; 667331c488dSSøren Schmidt 6685a5b148dSSøren Schmidt driver_t ata_pcichannel_driver = { 669331c488dSSøren Schmidt "ata", 6705a5b148dSSøren Schmidt ata_pcichannel_methods, 6716ddce903SSøren Schmidt sizeof(struct ata_channel), 672331c488dSSøren Schmidt }; 673331c488dSSøren Schmidt 6745a5b148dSSøren Schmidt DRIVER_MODULE(ata, atapci, ata_pcichannel_driver, ata_devclass, 0, 0); 675